Files
parr_api/PARR.API/Controllers/V1/JobController.cs
2023-09-26 14:43:25 +10:00

255 lines
12 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 Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PARR.API.Contracts.V1;
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.DAL.DomainModels;
using PARR.DAL.Models.V1;
using PARR.DAL.Services.Interfaces.V1;
namespace PARR.API.Controllers.V1
{
public class JobController : BaseApiController
{
private readonly IMapper mapper;
private readonly V1_IJobService jobService;
//private readonly ISchedulerService schedulerService;
private readonly IClientService clientService;
private readonly V1_IHostService v1_hostService;
private readonly V1_IJobJournalService jobJournalService;
public JobController(
IMapper mapper,
V1_IJobService jobService,
IClientService clientService,
V1_IHostService v1_hostService,
V1_IJobJournalService jobJournalService
)
{
this.mapper = mapper;
this.jobService = jobService;
//this.schedulerService = schedulerService;
this.clientService = clientService;
this.v1_hostService = v1_hostService;
this.jobJournalService = jobJournalService;
}
/// <summary>
/// (НЕ РАБОТАЕТ. АДАПТАЦИЯ ПОД НОВУЮ ВЕРСИЮ) Список всех jobов постранично в соотвествии с фильтрами
/// </summary>
/// <param name="paginationQuery"></param>
/// <returns></returns>
[HttpGet(ApiRoutes.Jobs.GetAll)]
public async Task<IActionResult> GetAll([FromQuery] PaginationQuery paginationQuery, [FromQuery] JobGetAllQuery filter)
{
var paginationFilter = mapper.Map<PaginationFilter>(paginationQuery);
IQueryable<V1_Job> query = jobService.Get().Include(t => t.JobMode).OrderBy(s => s.StartAt);
if (filter.IsEnabled.HasValue)
query = query.Where(t => t.IsEnabled == filter.IsEnabled);
if (filter.StartDatePlanned.HasValue)
query = query.Where(t => t.StartAt.DateTime.Date <= filter.StartDatePlanned.Value.DateTime.Date); ;
var jobs = await jobService.GetPage(query, paginationFilter).ToListAsync();
if (!jobs.Any())
return NoContent();
var jobResponse = mapper.Map<List<JobGetAllResponse>>(jobs);
var paginationResponse = new PagedResponse<JobGetAllResponse>(jobResponse, true).GetPaginatedProps(paginationFilter, query);
return Ok(paginationResponse);
}
/// <summary>
/// (НЕ РАБОТАЕТ. АДАПТАЦИЯ ПОД НОВУЮ ВЕРСИЮ) Список заданий на запуск по IP-адресу клиента исполнения
/// </summary>
/// <param name="requestQuery"></param>
/// <returns></returns>
[HttpGet(ApiRoutes.Jobs.GetByIp)]
public async Task<IActionResult> GetByClientIP([FromQuery] JobGetByIpQuery requestQuery)
{
var ip = requestQuery.Ip ?? clientService.GetClientIp()?.ToString();
if (string.IsNullOrEmpty(ip))
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Client IP address is null." } }));
var date = requestQuery.Date ?? DateTimeOffset.UtcNow;
// С одним IP может быть несколько информационных систем, соответственного а таблице храниться несколько записей хостов с одинаковым IP
var hosts = await v1_hostService.Get().Where(h => h.IP == ip).ToListAsync();
var hostJobsDict = new Dictionary<V1_Host, List<V1_Job>>();
foreach (var host in hosts)
{
var jobsHost = await jobService.Get()
.Include(a => a.Application).ThenInclude(ah => ah.ApplicationsInHosts)/*.ThenInclude(h => h.Host)*/
.Include(jm => jm.JobMode)
.AsSplitQuery()
.Where(j => j.Application != null && j.Application.ApplicationsInHosts.Any(ah => ah.HostId == host.Id) && j.IsEnabled && j.StartAt <= date)
.ToListAsync();
if (jobsHost.Any())
{
hostJobsDict.Add(host, jobsHost);
}
}
var jobsList = new List<V1_Job>();
var jobsToResponse = new List<V1_Job>();
foreach (var hostAndJobs in hostJobsDict)
{
foreach (var item in hostAndJobs.Value)
{
if (!jobsList.Contains(item))
{
jobsList.Add(item);
var plannedJobs = await GetListJobsAsync(item, hostAndJobs.Key, date);
jobsToResponse.AddRange(plannedJobs);
}
}
}
jobsToResponse = jobsToResponse.OrderBy(t => t.StartAt).ToList();
if (!jobsToResponse.Any())
return NoContent();
if (requestQuery.IsFullResponse == true)
{
// возврат самого полного ответа
var jobResponse = mapper.Map<List<JobGetAllResponse>>(jobsToResponse);
return Ok(new Response<List<JobGetAllResponse>>(jobResponse, true));
}
// возврат минимального ответа
return Ok(mapper.Map<JobMinResponse>(jobsToResponse));
//try
//{
// return Ok(jobsToResponse.ToDictionary(t => t.ScriptName, d => d.StartAt));
//}
//catch (ArgumentException ex)
//{
// return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Не могу создать json объект с одинаковым значением ключа (ScriptName). {ex.Message}" } }));
//}
}
private async Task<List<V1_Job>> GetListJobsAsync(V1_Job job, V1_Host host, DateTimeOffset queryDate)
{
var jobs = new List<V1_Job>();
#region description
// freaq > суток или нет?
//-----------
// меньше суток
//фрек=10 мин
// старт эт = 17:00 и != сегодня
//цикл 17:00 -10мин пока не начнется вчерашний день
//цикл 17:00 +10мин пока не начентся завтрашний день
// елси страт эт == сегодня
//цикл 17:00 +10мин пока не начентся завтрашний день
//-----------
// ------freaq больше суток--------
// журнал берем последнее событие (че там со статусами? не надо пока), к нему пребавляем фрек, и смотрим == сегодня или нет, если сегодня то добавляем
// --------------
#endregion
var allDayMinutes = 1440;
if (job.Frequency >= allDayMinutes)
{
//больше или = суток
var lastJournalItem = await jobJournalService.GetLastAsync(job.Id, host.Id, queryDate);
if (lastJournalItem == null)
{
// если в истории нет записей, то запускаем сегодня в стартЭт
// берем квери дэйт и ем задаем время из Джобс СтартЭт
var startDateTimeNext = new DateTimeOffset(queryDate.Year, queryDate.Month, queryDate.Day, job.StartAt.Hour, job.StartAt.Minute, job.StartAt.Second, new TimeSpan(0));
var jobToAdded = mapper.Map<V1_Job>(job);//new Job { StartAt = startDateTimeNext };
jobToAdded.StartAt = startDateTimeNext;
jobs.Add(jobToAdded);
}
else
{
var startDateNext = lastJournalItem.DateOper.DateTime.AddMinutes(job.Frequency);
if (startDateNext.Date == queryDate.DateTime.Date)
{
// если берем прошлую последнюю операцию из журнала, и к ней прибавить фрекунси, то время следующего старта сдвинется на время выполнения прошлого задания
// чтобы это избежать, берем квери дэйт и ем задаем время из Джобс СтартЭт
var startDateTimeNext = new DateTimeOffset(queryDate.Year, queryDate.Month, queryDate.Day, job.StartAt.Hour, job.StartAt.Minute, job.StartAt.Second, new TimeSpan(0));
var jobToAdded = mapper.Map<V1_Job>(job);
jobToAdded.StartAt = startDateTimeNext;
jobs.Add(jobToAdded);
}
}
}
else
{
//меньше суток
var startAtMinutes = (job.StartAt - job.StartAt.StartOfDay()).TotalMinutes;
// если дата старта != queryDate
if (job.StartAt.DateTime.Date != queryDate.DateTime.Date)
{
// отнимаем пока не наступили прошлые стуки
var min = startAtMinutes;
while (min >= 0)
{
//var jobToAdded = new Job { StartAt = queryDate.StartOfDay().AddMinutes(min) };
var jobToAdded = mapper.Map<V1_Job>(job);
jobToAdded.StartAt = queryDate.StartOfDay().AddMinutes(min);
jobs.Add(jobToAdded);
min = min - job.Frequency;
}
// прибавляем пока не наступят след сутки
min = startAtMinutes + job.Frequency;
while (min < allDayMinutes)
{
//var jobToAdded = new Job { StartAt = queryDate.StartOfDay().AddMinutes(min) };
var jobToAdded = mapper.Map<V1_Job>(job);
jobToAdded.StartAt = queryDate.StartOfDay().AddMinutes(min);
jobs.Add(jobToAdded);
min = min + job.Frequency;
}
}
else
{
// = queryDate
// прибавляем пока не наступят след сутки
var min = startAtMinutes;
while (min < allDayMinutes)
{
//var jobToAdded = new Job { StartAt = queryDate.StartOfDay().AddMinutes(min) };
var jobToAdded = mapper.Map<V1_Job>(job);
jobToAdded.StartAt = queryDate.StartOfDay().AddMinutes(min);
jobs.Add(jobToAdded);
min = min + job.Frequency;
}
}
}
return jobs;
}
}
}