Files
parr_api/PARR.API/Controllers/V1/ApplicationInWorkController.cs

394 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AutoMapper;
using FluentValidation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PARR.API.Contracts.V1;
using PARR.API.Contracts.V1.Requests;
using PARR.API.Contracts.V1.Requests.Queries;
using PARR.API.Contracts.V1.Responses;
using PARR.API.Contracts.V1.Responses.Base;
using PARR.API.Controllers.V1.Base;
using PARR.API.Extensions;
using PARR.API.Services.Interfaces;
using PARR.API.Settings;
using PARR.BLL.Domain.Mq;
using PARR.BLL.Services.Interfaces;
using PARR.Constants;
using PARR.DAL.DomainModels;
using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces;
using System.Text.Json;
namespace PARR.API.Controllers.V1
{
[Authorize(Roles = ParrRoles.Administrator.Role)]
public class ApplicationInWorkController : BaseApiController
{
private readonly ILogger<ApplicationInWorkController> logger;
private readonly IMapper mapper;
private readonly IApplicationsInWorkService applicationsInWorkService;
private readonly IValidator<ApplicationInWorkRequest> validator;
private readonly IUriService uriService;
private readonly ITemplateService templateService;
private readonly IMqService mqService;
private readonly MqSettings mqSettings;
public ApplicationInWorkController(
ILogger<ApplicationInWorkController> logger,
IMapper mapper,
IApplicationsInWorkService applicationsInWorkService,
IValidator<ApplicationInWorkRequest> validator,
IUriService uriService,
ITemplateService templateService,
IMqService mqService,
MqSettings mqSettings
)
{
this.logger = logger;
this.mapper = mapper;
this.applicationsInWorkService = applicationsInWorkService;
this.validator = validator;
this.uriService = uriService;
this.templateService = templateService;
this.mqService = mqService;
this.mqSettings = mqSettings;
}
/// <summary>
/// Получить список заданий на выполнение работ(ApplicationInWork) постранично
/// </summary>
/// <returns></returns>
[HttpGet(ApiRoutes.Job.GetAll)]
public async Task<IActionResult> GetAll([FromQuery] PaginationQuery paginationQuery, [FromQuery] ApplicationInWorkQuery filter)
{
var paginationFilter = mapper.Map<PaginationFilter>(paginationQuery);
IQueryable<ApplicationsInWork> query = applicationsInWorkService.Get().Include(t => t.Application).ThenInclude(t => t!.ApplicationType);
if (filter.IsLight != true)
{
query = query
.Include(t => t.Work)
//.Include(t => t.Templates) - большой запрос, делаем его отдельно
.Include(t => t.WorkGroups).ThenInclude(t => t.WorkGroup);
}
query = query.OrderBy(t => t.ShortDescription).ThenBy(t => t.Application!.Name);
if (!string.IsNullOrEmpty(filter.ShortDescription))
query = query.Where(t => t.ShortDescription.ToLower().Contains(filter.ShortDescription.ToLower()));
if (filter.WorkId.HasValue)
query = query.Where(t => t.WorkId == filter.WorkId.Value);
var appInWorks = await applicationsInWorkService.GetPage(query, paginationFilter).ToListAsync();
if (!appInWorks.Any())
return NoContent();
var response = mapper.Map<List<ApplicationInWorkResponse>>(appInWorks);
if (filter.IsLight != true)
{
//Если запрос не легкий, закгружаем кол-во шаблонов отдельно, это значительно ускоряет запрос
foreach (var item in response)
{
item.TemplatesCount = await templateService.Get().CountAsync(t => t.ApplicationInWorkId == item.Id);
}
}
var paginationResponse = new PagedResponse<ApplicationInWorkResponse>(response, true).GetPaginatedProps(paginationFilter, query);
return Ok(paginationResponse);
}
/// <summary>
/// Получить задание на выполнение работ по id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet(ApiRoutes.Job.Get)]
public async Task<IActionResult> GetById([FromRoute] Guid id)
{
var applicationInWork = await applicationsInWorkService.Get()
.Include(t => t.Application).ThenInclude(t => t!.ApplicationType)
.Include(t => t.Work)
//.Include(t => t.Templates)
.Include(t => t.WorkGroups).ThenInclude(t => t.WorkGroup)
.FirstOrDefaultAsync(t => t.Id == id);
if (applicationInWork == null)
return NotFound();
var response = mapper.Map<ApplicationInWorkResponse>(applicationInWork);
response.TemplatesCount = await templateService.Get().CountAsync(t => t.ApplicationInWorkId == id);
return Ok(new Response<ApplicationInWorkResponse>(response, true));
}
/// <summary>
/// Создать задание на выполнение работ (ApplicationInWork)
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost(ApiRoutes.Job.Create)]
public async Task<IActionResult> Create([FromBody] ApplicationInWorkRequest request)
{
var resultValidate = await validator.ValidateAsync(request);
if (!resultValidate.IsValid)
return BadRequest(new Response(resultValidate.Errors));
//уникальная запись по полям ApplicationId, WorkId
var existSameAiW = await applicationsInWorkService.GetAsync(request.ApplicationId, request.WorkId);
if (existSameAiW != null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Задание на выполнение работ с такими ПО и работой уже существует" } }));
var applicationInWork = new ApplicationsInWork
{
Id = Guid.NewGuid(),
WorkId = request.WorkId,
ApplicationId = request.ApplicationId,
TemplateDuration = request.TemplateDuration,
ShortDescription = request.ShortDescription.Trim(),
FullDescription = request.FullDescription.Trim(),
Solution = request.Solution.Trim(),
//NextRun = request.NextRun,
IsAutoDistributionEnabled = request.IsAutoDistributionEnabled,
ReferenceDate = request.ReferenceDate,
IsAgent = request.IsAgent,
AgentName = request.AgentName?.Trim(),
AgentTimeOutSec = request.AgentTimeOutSec,
AgentScript = request.AgentScript?.Trim()
};
//Добавляем настройки планировщика
request.Schedule.ForEach(item =>
{
applicationInWork.EsppSchValues.Add(new EsppSchValue
{
ApplicationsInWorkId = applicationInWork.Id,
TypeConfigId = item.TypeConfigId,
TypeValueId = item.TypeValueId
});
});
//Добавляем рабочие группы
request.WorkGroups.ForEach(workGroupId =>
{
applicationInWork.WorkGroups.Add(new AppInWorkInWorkGroup
{
ApplicationsInWorkId = applicationInWork.Id,
WorkGroupId = workGroupId
});
});
if (!await applicationsInWorkService.CreateAsync(applicationInWork) || !await applicationsInWorkService.CommitAsync())
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при созании задания на выполнение работ" } }));
logger.LogInformation($"Пользователь {User.Identity?.Name} добавил задание на выполнение работ: {applicationInWork.Id}, {applicationInWork.ShortDescription}, {applicationInWork.Solution}");
var createdApplicationInWork = await applicationsInWorkService.Get()
.Include(t => t.Application).ThenInclude(t => t!.ApplicationType)
.Include(t => t.Work)
//.Include(t => t.Templates)
.Include(t => t.WorkGroups).ThenInclude(t => t.WorkGroup)
.FirstAsync(t => t.Id == applicationInWork.Id);
var locationUri = uriService.GetUri(ApiRoutes.Job.Get, ApiRoutes.Job.getParam, createdApplicationInWork.Id);
var response = mapper.Map<ApplicationInWorkResponse>(createdApplicationInWork);
// так как мы только что создали AppInW, то у него нет шаблонов, смело ставим = 0 (ускоряем запрос)
response.TemplatesCount = 0;
return Created(locationUri, new Response<ApplicationInWorkResponse>(response, true));
}
/// <summary>
/// Обновить задание на выполнение работ (ApplicationInWork)
/// </summary>
/// <param name="id"></param>
/// <param name="request"></param>
/// <returns></returns>
[HttpPut(ApiRoutes.Job.Update)]
public async Task<IActionResult> Update([FromRoute] Guid id, [FromBody] ApplicationInWorkRequest request)
{
var resultValidate = await validator.ValidateAsync(request);
if (!resultValidate.IsValid)
return BadRequest(new Response(resultValidate.Errors));
//уникальная запись по полям ApplicationId, WorkId у которой id!=[FromRoute]id
var existSameAiW = await applicationsInWorkService.Get()
.FirstOrDefaultAsync(t => t.Id != id && t.ApplicationId == request.ApplicationId && t.WorkId == request.WorkId);
if (existSameAiW != null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Задание на выполнение работ с такими ПО и работой уже существует" } }));
var orig = await applicationsInWorkService.Get()
.Include(t => t.WorkGroups)
.Include(t => t.EsppSchValues)
.FirstOrDefaultAsync(t => t.Id == id);
if (orig == null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при изменении задания на выполнение работ. Не найдено задание с Id: {id}" } }));
//Расписание было изменено, ниже добавим задание в очередь на обновление расписаний у связанных шаблонов
var isScheduleChanged = IsScheduleChanged(orig, request);
orig.WorkId = request.WorkId;
orig.ApplicationId = request.ApplicationId;
orig.TemplateDuration = request.TemplateDuration;
orig.ShortDescription = request.ShortDescription.Trim();
orig.FullDescription = request.FullDescription.Trim();
orig.Solution = request.Solution.Trim();
//orig.NextRun = request.NextRun;
orig.ReferenceDate = request.ReferenceDate;
orig.IsAutoDistributionEnabled = request.IsAutoDistributionEnabled;
orig.IsAgent = request.IsAgent;
orig.AgentName = request.AgentName?.Trim();
orig.AgentTimeOutSec = request.AgentTimeOutSec;
orig.AgentScript = request.AgentScript?.Trim();
orig.DateModified = DateTimeOffset.UtcNow;
//обновляем планировщик
orig.EsppSchValues.Clear();
request.Schedule.ForEach(item =>
{
orig.EsppSchValues.Add(new EsppSchValue
{
ApplicationsInWorkId = orig.Id,
TypeConfigId = item.TypeConfigId,
TypeValueId = item.TypeValueId
});
});
//Обновляем рабочие группы
orig.WorkGroups.Clear();
request.WorkGroups.ForEach(workGroupId =>
{
orig.WorkGroups.Add(new AppInWorkInWorkGroup
{
ApplicationsInWorkId = orig.Id,
WorkGroupId = workGroupId
});
});
if (!await applicationsInWorkService.CommitAsync())
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при изменении задания на выполнение работ." } }));
logger.LogInformation($"Пользователь {User.Identity?.Name} обновил задание на выполнение работ: {orig.Id}," +
$" {orig.WorkId}, {orig.ApplicationId}, {orig.TemplateDuration}, {orig.ShortDescription}," +
$" {orig.FullDescription}, {orig.Solution}, {nameof(orig.IsAutoDistributionEnabled)}: {orig.IsAutoDistributionEnabled}, {orig.IsAgent}, {orig.AgentName}, {orig.AgentTimeOutSec}, {orig.AgentScript}");
if (isScheduleChanged)
{
//расписание было обновлено, отправим задание в очередь на перерасчет NextRun
var requestToMq = new TemplateDistributorMq
{
ApplicationInWorkId = id
};
var msg = JsonSerializer.Serialize(requestToMq);
logger.LogDebug($"Расписание в РР applicationInWorkId: {id} было изменено. Отправляем задание в очередь на перерасчет NextRun");
var sendResult = mqService.Send(mqSettings.TemplateDistributor, new[] { msg });
if (sendResult.IsSuccess)
logger.LogInformation($"Задание на перерасчет NextRun успешно отправлено в очередь MQ {mqSettings.TemplateDistributor.QueueName}");
else
logger.LogError($"Ошибка при отправке задания на перерасчет NextRun в очередь MQ {mqSettings.TemplateDistributor.QueueName}");
}
var updatedApplicationInWork = await applicationsInWorkService.Get()
.Include(t => t.Application).ThenInclude(t => t!.ApplicationType)
.Include(t => t.Work)
//.Include(t => t.Templates)
.Include(t => t.WorkGroups).ThenInclude(t => t.WorkGroup)
.FirstAsync(t => t.Id == orig.Id);
var response = mapper.Map<ApplicationInWorkResponse>(updatedApplicationInWork);
response.TemplatesCount = await templateService.Get().CountAsync(t => t.ApplicationInWorkId == id);
return Ok(new Response<ApplicationInWorkResponse>(response, true));
}
/// <summary>
/// Удалить задание на выполнение работ (только если нет связанных шаблонов)
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete(ApiRoutes.Job.Delete)]
public async Task<IActionResult> Delete([FromRoute] Guid id)
{
var applicationsInWork = await applicationsInWorkService.Get()
//.Include(t => t.Templates)
.FirstOrDefaultAsync(t => t.Id == id);
if (applicationsInWork == null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ. Не найдено задание на выполнение работ Id: {id}"
} }));
var templateCount = await templateService.Get().CountAsync(t => t.ApplicationInWorkId == id);
//if (applicationsInWork.Templates.Any())
if (templateCount > 0)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ. С данным заданием связаны шаблоны: {templateCount} шт."
} }));
if (!applicationsInWorkService.Delete(applicationsInWork) || !await applicationsInWorkService.CommitAsync())
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ"
} }));
logger.LogInformation($"Пользователь {User.Identity?.Name} удалил задание на выполнение работ: {applicationsInWork.Id},{applicationsInWork.WorkId}," +
$" {applicationsInWork.ApplicationId}, {applicationsInWork.TemplateDuration}, {applicationsInWork.ShortDescription}," +
$" {applicationsInWork.FullDescription}, {applicationsInWork.Solution}, {nameof(applicationsInWork.IsAutoDistributionEnabled)}: {applicationsInWork.IsAutoDistributionEnabled}, {applicationsInWork.IsAgent}," +
$" {applicationsInWork.AgentName}, {applicationsInWork.AgentTimeOutSec}, {applicationsInWork.AgentScript}");
return NoContent();
}
/// <summary>
/// Проверка, были ли изменения в расписании
/// </summary>
/// <param name="orig"></param>
/// <param name="request"></param>
/// <returns></returns>
private bool IsScheduleChanged(ApplicationsInWork orig, ApplicationInWorkRequest request)
{
var isScheduleChanged = false;
if (orig.ReferenceDate != request.ReferenceDate)
isScheduleChanged = true;
if (request.Schedule.Count() != orig.EsppSchValues.Count())
isScheduleChanged = true;
request.Schedule.ForEach(requestSchedule =>
{
var schExist = orig.EsppSchValues.FirstOrDefault(t => t.ApplicationsInWorkId == orig.Id
&& t.TypeValueId == requestSchedule.TypeValueId
&& t.TypeConfigId == requestSchedule.TypeConfigId);
if (schExist == null)
isScheduleChanged = true;
});
return isScheduleChanged;
}
}
}