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.Models; using PARR.DAL.Models.Job; using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces.Job; namespace PARR.API.Controllers.V1 { /// /// Управление группами работам /// [Authorize(Roles = ParrRoles.Administrator.Role)] public class JobGroupController : BaseApiController { private readonly ILogger logger; private readonly IMapper mapper; private readonly IUriService uriService; private readonly IJobGroupService groupService; private readonly IJobService jobService; private readonly IEsppSchTypeConfigService esppConfigService; private readonly IValidator validator; private readonly SettingsFromDb settingsFromDb; public JobGroupController( ILogger logger, IMapper mapper, IUriService uriService, IJobGroupService groupService, IJobService jobService, IEsppSchTypeConfigService esppConfigService, IValidator validator, SettingsFromDb settingsFromDb ) { this.logger = logger; this.mapper = mapper; this.uriService = uriService; this.groupService = groupService; this.jobService = jobService; this.esppConfigService = esppConfigService; this.validator = validator; this.settingsFromDb = settingsFromDb; } /// /// Получить список групп заданий на выполнение работ постранично /// /// [HttpGet(ApiRoutes.JobGroup.GetAll)] public async Task GetAll([FromQuery] PaginationQuery paginationQuery, [FromQuery] JobGroupQuery filter) { var paginationFilter = mapper.Map(paginationQuery); IQueryable query = groupService.Get(); query = query.OrderBy(t => t.GroupName); if (!string.IsNullOrEmpty(filter.Name)) query = query.Where(t => t.GroupName.ToLower().Contains(filter.Name.ToLower())); if (filter.IsFull) query = query.Include(t => t.Jobs).ThenInclude(t => t.Tnk); var jobGroups = await groupService.GetPage(query, paginationFilter).ToListAsync(); if (!jobGroups.Any()) return NoContent(); var response = mapper.Map>(jobGroups); if (filter.IsFull) foreach (var jobGroupResponse in response) await AppendMissingDataAsync(jobGroupResponse); var paginationResponse = new PagedResponse(response, true).GetPaginatedProps(paginationFilter, query); return Ok(paginationResponse); } /// /// Получить группу заданий на выполнение работ по id /// /// /// [HttpGet(ApiRoutes.JobGroup.Get)] public async Task GetById([FromRoute] Guid id) { var jobGroup = await groupService.Get() .Include(t => t.Jobs).ThenInclude(t => t.Tnk) .Include(t => t.EsppSchValues) .FirstOrDefaultAsync(t => t.Id == id); if (jobGroup == null) return NotFound(); var response = mapper.Map(jobGroup); return Ok(new Response(response, true)); } /// /// Создать группу заданий на выполнение работ (JobGroup) /// /// /// [HttpPost(ApiRoutes.JobGroup.Create)] public async Task Create([FromBody] JobGroupRequest request) { var resultValidate = await validator.ValidateAsync(request); if (!resultValidate.IsValid) return BadRequest(new Response(resultValidate.Errors)); var jobGroup = new JobGroup { Id = Guid.NewGuid(), GroupName = request.Name.Trim(), IsUmbrella = request.IsUmbrella, ShortDescription = request.ShortDescription.Trim(), FullDescription = request.FullDescription.Trim(), Solution = request.Solution.Trim(), TemplateDuration = request.TemplateDuration.Trim(), ReferenceDate = request.ReferenceDate, //IsAutoDistributionEnabled = request.IsAutoDistributionEnabled, //IsAgent = request.IsAgent, //AgentName = request.AgentName, //AgentTimeOutSec = request.AgentTimeOutSec, //AgentScript = request.AgentScript }; //Добавляем настройки планировщика request.Schedule.ForEach(item => { jobGroup.EsppSchValues.Add(new EsppSchValue { JobGroupId = jobGroup.Id, TypeConfigId = item.TypeConfigId, TypeValueId = item.TypeValueId }); }); if (!await groupService.CreateAsync(jobGroup) || !await groupService.CommitAsync()) return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при создании группы заданий на выполнение работ" } })); logger.LogInformation($"Пользователь {User.Identity?.Name} добавил группу заданий на выполнение работ: {jobGroup.Id}, {jobGroup.GroupName}, {jobGroup.ShortDescription}"); var createdJobGroup = await groupService.Get().Include(t => t.Jobs).ThenInclude(t => t.Tnk) .FirstAsync(t => t.Id == jobGroup.Id); var locationUri = uriService.GetUri(ApiRoutes.JobGroup.Get, ApiRoutes.JobGroup.getParam, createdJobGroup.Id); var response = mapper.Map(createdJobGroup); return Created(locationUri, new Response(response, true)); } /// /// Обновить группу заданий на выполнение работ (JobGroup) /// /// /// /// [HttpPut(ApiRoutes.JobGroup.Update)] public async Task Update([FromRoute] Guid id, [FromBody] JobGroupRequest request) { var resultValidate = await validator.ValidateAsync(request); if (!resultValidate.IsValid) return BadRequest(new Response(resultValidate.Errors)); var orig = await groupService.Get() .Include(t => t.Jobs) .ThenInclude(t => t.Tnk) .Include(t => t.EsppSchValues) .FirstOrDefaultAsync(t => t.Id == id); if (orig == null) return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при изменении группы заданий на выполнение работ. Не найдена группа с Id: {id}" } })); // //Расписание было изменено, ниже добавим задание в очередь на обновление расписаний у связанных шаблонов var isScheduleChanged = IsScheduleChanged(orig, request); orig.GroupName = request.Name.Trim(); orig.IsUmbrella = request.IsUmbrella; orig.ShortDescription = request.ShortDescription.Trim(); orig.FullDescription = request.FullDescription.Trim(); orig.Solution = request.Solution.Trim(); orig.TemplateDuration = request.TemplateDuration.Trim(); orig.ReferenceDate = request.ReferenceDate; //orig.IsAutoDistributionEnabled = request.IsAutoDistributionEnabled; //orig.IsAgent = request.IsAgent; //orig.AgentName = request.AgentName; //orig.AgentTimeOutSec = request.AgentTimeOutSec; //orig.AgentScript = request.AgentScript; orig.DateModified = DateTimeOffset.UtcNow; //обновляем планировщик orig.EsppSchValues.Clear(); request.Schedule.ForEach(item => { orig.EsppSchValues.Add(new EsppSchValue { JobGroupId = orig.Id, TypeConfigId = item.TypeConfigId, TypeValueId = item.TypeValueId }); }); if (!await groupService.CommitAsync()) return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при изменении группы заданий на выполнение работ." } })); logger.LogInformation($"Пользователь {User.Identity?.Name} обновил группу заданий на выполнение работ: {orig.Id}," + $" {orig.GroupName}, {orig.IsUmbrella}, {orig.ShortDescription}, {orig.FullDescription}," + $" {orig.Solution}, {orig.TemplateDuration}, {orig.ReferenceDate}, {orig.IsAutoDistributionEnabled}" + $", {orig.IsAgent}, {orig.AgentName}, {orig.AgentTimeOutSec}, {orig.AgentScript}"); //TODO: Восстановить после перехода на JobGroup //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 updatedJobGroup = await groupService.Get() .Include(t => t.Jobs) .ThenInclude(t => t.Tnk) .FirstAsync(t => t.Id == orig.Id); var response = mapper.Map(updatedJobGroup); return Ok(new Response(response, true)); } /// /// Удалить группу заданий на выполнение работ (только если нет связанных заданий) /// /// /// [HttpDelete(ApiRoutes.JobGroup.Delete)] public async Task Delete([FromRoute] Guid id) { var jobGroup = await groupService.Get() .FirstOrDefaultAsync(t => t.Id == id); if (jobGroup == null) return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении группы заданий на выполнение работ. Не найдена группа заданий на выполнение работ Id: {id}" } })); var jobCount = await jobService.Get().CountAsync(t => t.GroupId == id); if (jobCount > 0) return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении группы заданий на выполнение работ. С данным группой связаны задания: {jobCount} шт." } })); if (!groupService.Delete(jobGroup) || !await groupService.CommitAsync()) return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении группы заданий на выполнение работ" } })); logger.LogInformation($"Пользователь {User.Identity?.Name} удалил группу заданий на выполнение работ: {jobGroup.Id},{jobGroup.GroupName}," + $" {jobGroup.IsUmbrella}, {jobGroup.ShortDescription}, {jobGroup.FullDescription}," + $" {jobGroup.Solution}, {jobGroup.TemplateDuration}, {jobGroup.ReferenceDate}" + $"{jobGroup.IsAutoDistributionEnabled}, {jobGroup.IsAgent}, {jobGroup.AgentName}" + $"{jobGroup.AgentTimeOutSec}, {jobGroup.AgentScript}"); return NoContent(); } /// /// Проверка, были ли изменения в расписании /// /// /// /// private bool IsScheduleChanged(JobGroup orig, JobGroupRequest request) { var isScheduleChanged = false; if (orig.ReferenceDate != request.ReferenceDate) isScheduleChanged = true; if (request.Schedule.Count() != orig.EsppSchValues.Count()) isScheduleChanged = true; //if (request.IsAutoDistributionEnabled != orig.IsAutoDistributionEnabled) // isScheduleChanged = true; request.Schedule.ForEach(requestSchedule => { var schExist = orig.EsppSchValues.FirstOrDefault(t => t.JobGroupId == orig.Id && t.TypeValueId == requestSchedule.TypeValueId && t.TypeConfigId == requestSchedule.TypeConfigId); if (schExist == null) isScheduleChanged = true; }); return isScheduleChanged; } private async Task AppendMissingDataAsync(JobGroupResponse jobGroupResponse) { var schedule = await esppConfigService.GetEsppScheduleDtoAsync(jobGroupResponse.Id); if (schedule == null) { logger.LogError($"Не смог замапить расписание, так как оно null. JobGroupId: {jobGroupResponse.Id}"); return; } var scheduleResponse = new JobGroupScheduleResponse { Timezone = settingsFromDb.ScheduleTimezone, TypeSchedule = mapper.Map(schedule.TypeSchedule), Values = mapper.Map>(schedule.Values).OrderBy(t => t.Order).ToList() }; jobGroupResponse.Schedule = scheduleResponse; jobGroupResponse.JobsCount = await jobService.Get().CountAsync(t => t.GroupId == jobGroupResponse.Id); } } }