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

354 lines
16 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.Constants;
using PARR.DAL.Contracts;
using PARR.DAL.DomainModels;
using PARR.DAL.DomainServices.Interfaces;
using PARR.DAL.Models.Job;
using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Job;
using PARR.DAL.Services.Interfaces.Unit;
namespace PARR.API.Controllers.V1
{
/// <summary>
/// Управление работами
/// </summary>
[Authorize(Roles = ParrRoles.Administrator.Role)]
public class JobController : BaseApiController
{
private readonly ILogger<JobController> logger;
private readonly IMapper mapper;
private readonly IUriService uriService;
private readonly IJobService jobService;
private readonly ITemplateService templateService;
private readonly IJobGroupService jobGroupService;
private readonly IValidator<JobRequest> jobValidator;
private readonly IUnitFilterService unitFilterService;
private readonly IUnitService unitService;
public JobController(
ILogger<JobController> logger,
IMapper mapper,
IUriService uriService,
IJobService jobService,
ITemplateService templateService,
IJobGroupService jobGroupService,
IValidator<JobRequest> jobValidator,
IUnitFilterService unitFilterService,
IUnitService unitService
)
{
this.logger = logger;
this.mapper = mapper;
this.uriService = uriService;
this.jobService = jobService;
this.templateService = templateService;
this.jobGroupService = jobGroupService;
this.jobValidator = jobValidator;
this.unitFilterService = unitFilterService;
this.unitService = unitService;
}
/// <summary>
/// Получить список заданий на выполнение работ(Job) постранично
/// </summary>
/// <returns></returns>
[HttpGet(ApiRoutes.Job.GetAll)]
public async Task<IActionResult> GetAll([FromQuery] PaginationQuery paginationQuery, [FromQuery] JobQuery filter)
{
var paginationFilter = mapper.Map<PaginationFilter>(paginationQuery);
IQueryable<Job> query = jobService.Get();
query = query.OrderBy(t => t.Name);
if (!string.IsNullOrEmpty(filter.Name))
query = query.Where(t => t.Name.ToLower().Contains(filter.Name.ToLower()));
if (filter.GroupId.HasValue)
query = query.Where(t => t.GroupId == filter.GroupId.Value);
if (filter.IsFull)
{
query = query
.Include(t => t.Tnk)
.Include(t => t.Group);
query = query
.Include(t => t.UnitFilters)
.ThenInclude(t => t.FieldFilters)
.ThenInclude(t => t.Field)
.Include(t => t.UnitFilters)
.ThenInclude(t => t.RelationshipFilters)
.ThenInclude(t => t.UnitField);
}
var jobs = await jobService.GetPage(query, paginationFilter).ToListAsync();
if (!jobs.Any())
return NoContent();
var response = mapper.Map<List<JobResponse>>(jobs);//TODO Migration to job
foreach (var jobResponse in response)
{
jobResponse.TemplatesCount = await templateService.Get().CountAsync(t => t.JobId == jobResponse.Id);
}
var paginationResponse = new PagedResponse<JobResponse>(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 job = await jobService.Get()
.Include(t => t.Tnk)
.Include(t => t.Group)
.Include(t => t.UnitFilters)
.ThenInclude(t => t.FieldFilters)
.ThenInclude(t => t.Field)
.Include(t => t.UnitFilters)
.ThenInclude(t => t.RelationshipFilters)
.FirstOrDefaultAsync(t => t.Id == id);
if (job == null)
return NotFound();
var response = mapper.Map<JobResponse>(job);
response.TemplatesCount = await templateService.Get().CountAsync(t => t.JobId == id);
var statistics = await GetStatisticsAsync(response.Id);
BindStatistics(response, statistics);
return Ok(new Response<JobResponse>(response, true));
}
/// <summary>
/// Создать задание на выполнение работ (Job)
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost(ApiRoutes.Job.Create)]
public async Task<IActionResult> Create([FromBody] JobRequest request)
{
#region Валидация
var jobValidateResult = await jobValidator.ValidateAsync(request);//Валидация параметров самого задания
if (!jobValidateResult.IsValid)
return BadRequest(new Response(jobValidateResult.Errors));
#endregion
var job = mapper.Map<Job>(request);
if (!await jobService.CreateAsync(job) || !await jobService.CommitAsync())
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при созании задания на выполнение работ" } }));
logger.LogInformation($"Пользователь {User.Identity?.Name} добавил задание на выполнение работ: {job.Id}, {job.Name}, {job.WorkName}");
var createdJob = await jobService.Get()
.Include(t => t.Tnk)
.Include(t => t.Group)
.Include(t => t.UnitFilters)
.ThenInclude(t => t.FieldFilters)
.ThenInclude(t => t.Field)
.Include(t => t.UnitFilters)
.ThenInclude(t => t.RelationshipFilters)
.FirstOrDefaultAsync(t => t.Id == job.Id);
var locationUri = uriService.GetUri(ApiRoutes.Job.Get, ApiRoutes.Job.getParam, createdJob!.Id);
var response = mapper.Map<JobResponse>(createdJob);
// так как мы только что создали Job, то у него нет шаблонов, смело ставим = 0 (ускоряем запрос)
response.TemplatesCount = 0;
return Created(locationUri, new Response<JobResponse>(response, true));
}
/// <summary>
/// Обновить задание на выполнение работ (Job)
/// </summary>
/// <param name="id"></param>
/// <param name="request"></param>
/// <returns></returns>
[HttpPut(ApiRoutes.Job.Update)]
public async Task<IActionResult> Update([FromRoute] Guid id, [FromBody] JobRequest request)
{
var resultValidate = await jobValidator.ValidateAsync(request);
if (!resultValidate.IsValid)
return BadRequest(new Response(resultValidate.Errors));
var orig = await jobService.Get().Include(t => t.Tnk)
.FirstOrDefaultAsync(t => t.Id == id);
if (orig == null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при изменении задания на выполнение работ. Не найдено задание с Id: {id}" } }));
orig.Name = request.Name.Trim();
orig.WorkName = request.WorkName.Trim();
orig.MinValueRelationships = request.MinValueRelationships;
orig.MaxValueRelationships = request.MaxValueRelationships;
orig.isParentRelationships = request.isParentRelationships;
orig.TemplateNameMask = request.TemplateNameMask.Trim();
orig.WorkGroupMask = request.WorkGroupMask.Trim();
orig.TnkId = request.TnkId;
orig.GroupId = request.GroupId;
if (!await jobService.CommitAsync())
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при изменении задания на выполнение работ." } }));
logger.LogInformation($"Пользователь {User.Identity?.Name} обновил задание на выполнение работ: {orig.Id}," +
$" {orig.Name}, {orig.WorkName}, {orig.MinValueRelationships}, {orig.MaxValueRelationships}," +
$" {orig.TemplateNameMask}, {orig.TnkId}, {nameof(orig.GroupId)}");
var updatedApplicationInWork = await jobService.Get().Include(t => t.Tnk)
.FirstAsync(t => t.Id == orig.Id);
var response = mapper.Map<JobResponse>(updatedApplicationInWork);
response.TemplatesCount = await templateService.Get().CountAsync(t => t.JobId == id);
var statistics = await GetStatisticsAsync(response.Id);
BindStatistics(response, statistics);
return Ok(new Response<JobResponse>(response, true));
}
/// <summary>
/// Удалить задание на выполнение работ (только если нет связанных шаблонов)
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete(ApiRoutes.Job.Delete)]
public async Task<IActionResult> Delete([FromRoute] Guid id)
{
var job = await jobService.Get().Include(t => t.Tnk)
.FirstOrDefaultAsync(t => t.Id == id);
if (job == null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ. Не найдено задание на выполнение работ Id: {id}"
} }));
var templateCount = await templateService.Get().CountAsync(t => t.JobId == id);
if (templateCount > 0)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ. С данным заданием связаны шаблоны: {templateCount} шт."
} }));
if (!jobService.Delete(job) || !await jobService.CommitAsync())
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ"
} }));
logger.LogInformation($"Пользователь {User.Identity?.Name} удалил задание на выполнение работ: {job.Id},{job.Name}," +
$" {job.WorkName}, {job.MinValueRelationships}, {job.MaxValueRelationships}," +
$" {job.TemplateNameMask}, {job.TnkId}, {job.GroupId}");
return NoContent();
}
/// <summary>
/// Получить список ЭК для которых будут созданы шаблоны
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost(ApiRoutes.Job.Preview)]
public async Task<IActionResult> Preview([FromBody] JobRequest request)
{
#region Валидация
var jobValidateResult = await jobValidator.ValidateAsync(request);//Валидация параметров самого задания
if (!jobValidateResult.IsValid)
return BadRequest(new Response(jobValidateResult.Errors));
#endregion
var job = mapper.Map<Job>(request);
var group = await jobGroupService.GetAsync(request.GroupId);
job.Group = group;
var unitIds = await unitFilterService.GetUnitsIdByJobFilterAsync(job);
if (unitIds == null)
return NotFound();
var units = await unitService.Get().Where(t => unitIds.Any(a => a == t.Id)).Take(1000).ToListAsync();
var response = mapper.Map<List<UnitResponse>>(units);
return Ok(response);
}
/// <summary>
/// Загрузка статистики
/// </summary>
/// <param name="jobId"></param>
/// <returns></returns>
private async Task<JobStatModel> GetStatisticsAsync(Guid jobId)
{
var statResult = await jobService.Get()
.Include(t => t.Templates)
.ThenInclude(t => t.RobotConfigurations)
.Where(x => x.Id == jobId)
.Select(t => new
{
TemplateActivated = t.Templates.Count(x => x.IsActiveTemplate),
TemplateSynchronized = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.TaskStatusCode == (int)TaskStatusEnum.Ok && c.RobotCode == (int)RobotsEnum.TemplateOrder)),
TemplateErrors = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.RobotStatusCode == (int)RobotStatusEnum.Error && c.RobotCode == (int)RobotsEnum.TemplateOrder)),
ScheduleActivated = t.Templates.Count(x => x.IsActiveSchedule),
ScheduleSynchronized = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.TaskStatusCode == (int)TaskStatusEnum.Ok && c.RobotCode == (int)RobotsEnum.ScheduleOrder)),
ScheduleErrors = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.RobotStatusCode == (int)RobotStatusEnum.Error && c.RobotCode == (int)RobotsEnum.ScheduleOrder))
}).FirstOrDefaultAsync();
return new JobStatModel
{
ScheduleStatistics = new ScheduleStats { Activated = statResult?.ScheduleActivated ?? 0, Errors = statResult?.ScheduleErrors ?? 0, Synchronized = statResult?.ScheduleSynchronized ?? 0 },
TemplateStatistics = new TemplateStats { Activated = statResult?.TemplateActivated ?? 0, Errors = statResult?.TemplateErrors ?? 0, Synchronized = statResult?.TemplateSynchronized ?? 0 }
};
}
private void BindStatistics(JobResponse job, JobStatModel statistics)
{
//job.TemplateStatistics = new TemplateStats { Activated = statistics.TemplateStatistics.Activated, Errors = statistics.TemplateStatistics.Errors, Synchronized = statistics.TemplateStatistics.Synchronized };
//job.ScheduleStatistics = new ScheduleStats { Activated = statistics.ScheduleStatistics.Activated, Errors = statistics.ScheduleStatistics.Errors, Synchronized = statistics.ScheduleStatistics.Synchronized };
}
}
public class JobStatModel
{
public required TemplateStats TemplateStatistics { get; set; }
public required ScheduleStats ScheduleStatistics { get; set; }
}
}