feat(api,core,domain): Получение снапшотов работы роботов
This commit is contained in:
@@ -258,6 +258,7 @@
|
|||||||
|
|
||||||
public static class StatRobotSnapshot
|
public static class StatRobotSnapshot
|
||||||
{
|
{
|
||||||
|
public const string GetAll = BaseStat + "/robot-snapshots/";
|
||||||
public const string Create = BaseStat + "/robot-snapshots/";
|
public const string Create = BaseStat + "/robot-snapshots/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
namespace PARR.API.Contracts.V1.Requests.Queries
|
||||||
|
{
|
||||||
|
public record StatRobotSnapshotQuery
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// IP робота
|
||||||
|
/// </summary>
|
||||||
|
public string? Ip { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Кол-во минут от текущего времени, по умолчнию 12 часов.
|
||||||
|
/// </summary>
|
||||||
|
public int Minutes { get; init; } = 12 * 60;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
namespace PARR.API.Contracts.V1.Responses.Statistics
|
namespace PARR.API.Contracts.V1.Responses.Statistics
|
||||||
{
|
{
|
||||||
public record StatRobotSnapshotItemResponse
|
public record StatRobotSnapshotItemResponse
|
||||||
|
{
|
||||||
|
public required UserBaseResponse Robot { get; init; }
|
||||||
|
|
||||||
|
public List<StatRobotSnapshotResponse> Snapshots { get; init; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public record StatRobotSnapshotResponse
|
||||||
{
|
{
|
||||||
public Guid Id { get; init; }
|
public Guid Id { get; init; }
|
||||||
|
|
||||||
@@ -11,7 +18,5 @@
|
|||||||
public int ScheduleRobotsCount { get; init; }
|
public int ScheduleRobotsCount { get; init; }
|
||||||
|
|
||||||
public int MaxRobots { get; init; }
|
public int MaxRobots { get; init; }
|
||||||
|
|
||||||
public required string Ip { get; init; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using PARR.API.Contracts.V1;
|
using PARR.API.Contracts.V1;
|
||||||
using PARR.API.Contracts.V1.Requests;
|
using PARR.API.Contracts.V1.Requests;
|
||||||
|
using PARR.API.Contracts.V1.Requests.Queries;
|
||||||
using PARR.API.Contracts.V1.Responses.Base;
|
using PARR.API.Contracts.V1.Responses.Base;
|
||||||
using PARR.API.Contracts.V1.Responses.Statistics;
|
using PARR.API.Contracts.V1.Responses.Statistics;
|
||||||
using PARR.API.Controllers.V1.Base;
|
using PARR.API.Controllers.V1.Base;
|
||||||
@@ -13,7 +14,7 @@ using PARR.Domain.DTOs.RobotSnapshotDTO;
|
|||||||
|
|
||||||
namespace PARR.API.Controllers.V1.Statistics
|
namespace PARR.API.Controllers.V1.Statistics
|
||||||
{
|
{
|
||||||
[Authorize(Roles = ParrRoles.Administrator.Role)]
|
[Authorize]
|
||||||
public class StatRobotSnapshotController : BaseApiController
|
public class StatRobotSnapshotController : BaseApiController
|
||||||
{
|
{
|
||||||
private readonly IRobotSnapshotService robotSnapshotService;
|
private readonly IRobotSnapshotService robotSnapshotService;
|
||||||
@@ -31,6 +32,28 @@ namespace PARR.API.Controllers.V1.Statistics
|
|||||||
this.clientService = clientService;
|
this.clientService = clientService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить снапшоты роботов.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Authorize(Roles = ParrRoles.Administrator.Role)]
|
||||||
|
[HttpGet(ApiRoutes.StatRobotSnapshot.GetAll)]
|
||||||
|
public async Task<IActionResult> GetAll([FromQuery] StatRobotSnapshotQuery query)
|
||||||
|
{
|
||||||
|
var queryDto = mapper.Map<RobotSnapshotQuery>(query);
|
||||||
|
|
||||||
|
var snapshots = await robotSnapshotService.GetAsync(queryDto);
|
||||||
|
|
||||||
|
if (snapshots.Count == 0)
|
||||||
|
return NoContent();
|
||||||
|
|
||||||
|
var response = mapper.Map<List<StatRobotSnapshotItemResponse>>(snapshots);
|
||||||
|
|
||||||
|
return Ok(new Response<List<StatRobotSnapshotItemResponse>>(response, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Отправить снапшот роботов.
|
/// Отправить снапшот роботов.
|
||||||
/// Доступ только с ролью "Робот ЕСПП"
|
/// Доступ только с ролью "Робот ЕСПП"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using PARR.Domain.DTOs.RobotSnapshotDTO;
|
|||||||
using PARR.Domain.DTOs.RobotTask;
|
using PARR.Domain.DTOs.RobotTask;
|
||||||
using PARR.Domain.DTOs.Shortcode;
|
using PARR.Domain.DTOs.Shortcode;
|
||||||
using PARR.Domain.DTOs.TaskDTO;
|
using PARR.Domain.DTOs.TaskDTO;
|
||||||
|
using PARR.Domain.DTOs.User;
|
||||||
using PARR.Domain.DTOs.Workload;
|
using PARR.Domain.DTOs.Workload;
|
||||||
using PARR.Domain.Entities;
|
using PARR.Domain.Entities;
|
||||||
using PARR.Domain.Entities.Base.History;
|
using PARR.Domain.Entities.Base.History;
|
||||||
@@ -312,6 +313,8 @@ namespace PARR.API.MappingProfiles
|
|||||||
|
|
||||||
CreateMap<UserCache, UserProfileResponse>();
|
CreateMap<UserCache, UserProfileResponse>();
|
||||||
|
|
||||||
|
CreateMap<UserBaseDto, UserBaseResponse>();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Order
|
#region Order
|
||||||
@@ -486,8 +489,13 @@ namespace PARR.API.MappingProfiles
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region RobotSnapshot
|
||||||
|
|
||||||
CreateMap<RobotSnapshotItem, StatRobotSnapshotItemResponse>();
|
CreateMap<RobotSnapshotDto, StatRobotSnapshotResponse>();
|
||||||
|
|
||||||
|
CreateMap<RobotSnapshotItemDto, StatRobotSnapshotItemResponse>();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using PARR.API.Contracts.V1.Requests;
|
using PARR.API.Contracts.V1.Requests;
|
||||||
using PARR.API.Contracts.V1.Requests.Queries;
|
using PARR.API.Contracts.V1.Requests.Queries;
|
||||||
using PARR.Domain.Common.Pagination;
|
using PARR.Domain.Common.Pagination;
|
||||||
|
using PARR.Domain.DTOs.RobotSnapshotDTO;
|
||||||
using PARR.Domain.Entities.Job;
|
using PARR.Domain.Entities.Job;
|
||||||
|
|
||||||
namespace PARR.API.MappingProfiles
|
namespace PARR.API.MappingProfiles
|
||||||
@@ -45,6 +46,8 @@ namespace PARR.API.MappingProfiles
|
|||||||
CreateMap<RelationshipFilterRequest, JobRelationshipFilter>();
|
CreateMap<RelationshipFilterRequest, JobRelationshipFilter>();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
CreateMap<StatRobotSnapshotQuery, RobotSnapshotQuery>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace PARR.Core.Infrastructure.Mapping.RobotSnapshot
|
|||||||
{
|
{
|
||||||
public RobotSnapshotMappingProfile()
|
public RobotSnapshotMappingProfile()
|
||||||
{
|
{
|
||||||
CreateMap<PARR.Domain.Entities.RobotEntities.RobotSnapshot, RobotSnapshotItem>();
|
CreateMap<PARR.Domain.Entities.RobotEntities.RobotSnapshot, RobotSnapshotDto>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
|||||||
{
|
{
|
||||||
public interface IRobotSnapshotService
|
public interface IRobotSnapshotService
|
||||||
{
|
{
|
||||||
Task<RobotSnapshotItem> CreateAsync(CreateRobotSnapshot robotSnapshot);
|
Task<List<RobotSnapshotItemDto>> GetAsync(RobotSnapshotQuery queryDto);
|
||||||
|
|
||||||
|
Task<RobotSnapshotItemDto> CreateAsync(CreateRobotSnapshot robotSnapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using PARR.Core.Repositories.Interfaces;
|
||||||
using PARR.Core.Repositories.Interfaces.RobotRepositories;
|
using PARR.Core.Repositories.Interfaces.RobotRepositories;
|
||||||
using PARR.Domain.DTOs.RobotSnapshotDTO;
|
using PARR.Domain.DTOs.RobotSnapshotDTO;
|
||||||
|
using PARR.Domain.DTOs.User;
|
||||||
using PARR.Domain.Entities.RobotEntities;
|
using PARR.Domain.Entities.RobotEntities;
|
||||||
using PARR.Domain.Exceptions;
|
using PARR.Domain.Exceptions;
|
||||||
|
|
||||||
@@ -9,19 +12,63 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
|||||||
internal class RobotSnapshotService : IRobotSnapshotService
|
internal class RobotSnapshotService : IRobotSnapshotService
|
||||||
{
|
{
|
||||||
private readonly IRobotSnapshotRepository robotSnapshotRepository;
|
private readonly IRobotSnapshotRepository robotSnapshotRepository;
|
||||||
|
private readonly IUserRepository userRepository;
|
||||||
private readonly IMapper mapper;
|
private readonly IMapper mapper;
|
||||||
|
|
||||||
public RobotSnapshotService(
|
public RobotSnapshotService(
|
||||||
IRobotSnapshotRepository robotSnapshotRepository,
|
IRobotSnapshotRepository robotSnapshotRepository,
|
||||||
|
IUserRepository userRepository,
|
||||||
IMapper mapper
|
IMapper mapper
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.robotSnapshotRepository = robotSnapshotRepository;
|
this.robotSnapshotRepository = robotSnapshotRepository;
|
||||||
|
this.userRepository = userRepository;
|
||||||
this.mapper = mapper;
|
this.mapper = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<RobotSnapshotItem> CreateAsync(CreateRobotSnapshot robotSnapshot)
|
public async Task<List<RobotSnapshotItemDto>> GetAsync(RobotSnapshotQuery queryDto)
|
||||||
|
{
|
||||||
|
// Просто возвращаем данные из БД, не проверяем что есть промежутки между которыми не было данных
|
||||||
|
// Т.е это просто чтоб посмотреть что есть в БД
|
||||||
|
|
||||||
|
var minutes = queryDto.Minutes > 0 ? queryDto.Minutes : 60 * 12;
|
||||||
|
|
||||||
|
var dateEnd = DateTimeOffset.UtcNow;
|
||||||
|
var dateStart = dateEnd.AddMinutes(-minutes);
|
||||||
|
|
||||||
|
var query = robotSnapshotRepository.Get().AsNoTracking()
|
||||||
|
.Where(t => dateStart <= t.DateCreated && t.DateCreated <= dateEnd);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(queryDto.Ip))
|
||||||
|
query = query.Where(t => t.Ip == queryDto.Ip);
|
||||||
|
|
||||||
|
var groupingSnapshots = (await query.ToListAsync()).GroupBy(t => t.Ip);
|
||||||
|
|
||||||
|
|
||||||
|
var robotIps = groupingSnapshots.Select(t => t.Key).ToHashSet();
|
||||||
|
var robotList = await userRepository.Get()
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(t => robotIps.Contains(t.Ip))
|
||||||
|
.ToDictionaryAsync(t => t.Ip);
|
||||||
|
|
||||||
|
var result = new List<RobotSnapshotItemDto>();
|
||||||
|
|
||||||
|
foreach (var item in groupingSnapshots)
|
||||||
|
{
|
||||||
|
robotList.TryGetValue(item.Key, out var robot);
|
||||||
|
|
||||||
|
var userDto = new UserBaseDto { Ip = item.Key, Description = robot?.Description ?? string.Empty, Name = robot?.Name ?? string.Empty };
|
||||||
|
var snapshots = mapper.Map<List<RobotSnapshotDto>>(item).OrderBy(t => t.DateCreated).ToList();
|
||||||
|
|
||||||
|
result.Add(new RobotSnapshotItemDto { Robot = userDto, Snapshots = snapshots });
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.OrderBy(t => t.Robot.Ip).ThenBy(t => t.Robot.Name).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<RobotSnapshotItemDto> CreateAsync(CreateRobotSnapshot robotSnapshot)
|
||||||
{
|
{
|
||||||
var snapshot = new RobotSnapshot
|
var snapshot = new RobotSnapshot
|
||||||
{
|
{
|
||||||
@@ -38,7 +85,16 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
|||||||
if (!createdResult || !commitResult)
|
if (!createdResult || !commitResult)
|
||||||
throw new DbErrorException("Ошибка сохранения в БД");
|
throw new DbErrorException("Ошибка сохранения в БД");
|
||||||
|
|
||||||
return mapper.Map<RobotSnapshotItem>(snapshot);
|
var user = await userRepository.Get().AsNoTracking().FirstOrDefaultAsync(t => t.Ip == robotSnapshot.Ip);
|
||||||
|
var userDto = new UserBaseDto { Ip = robotSnapshot.Ip, Description = user?.Description ?? string.Empty, Name = user?.Name ?? string.Empty };
|
||||||
|
|
||||||
|
var result = new RobotSnapshotItemDto
|
||||||
|
{
|
||||||
|
Robot = userDto,
|
||||||
|
Snapshots = mapper.Map<List<RobotSnapshotDto>>(new List<RobotSnapshot> { snapshot })
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
namespace PARR.Domain.DTOs.RobotSnapshotDTO
|
|
||||||
{
|
|
||||||
public record RobotSnapshotItem
|
|
||||||
{
|
|
||||||
public Guid Id { get; init; }
|
|
||||||
|
|
||||||
public DateTimeOffset DateCreated { get; init; }
|
|
||||||
|
|
||||||
public int TemplateRobotsCount { get; init; }
|
|
||||||
|
|
||||||
public int ScheduleRobotsCount { get; init; }
|
|
||||||
|
|
||||||
public int MaxRobots { get; init; }
|
|
||||||
|
|
||||||
public required string Ip { get; init; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
26
PARR.Domain/DTOs/RobotSnapshotDTO/RobotSnapshotItemDto.cs
Normal file
26
PARR.Domain/DTOs/RobotSnapshotDTO/RobotSnapshotItemDto.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
|
||||||
|
using PARR.Domain.DTOs.User;
|
||||||
|
|
||||||
|
namespace PARR.Domain.DTOs.RobotSnapshotDTO
|
||||||
|
{
|
||||||
|
public record RobotSnapshotItemDto
|
||||||
|
{
|
||||||
|
public required UserBaseDto Robot { get; init; }
|
||||||
|
|
||||||
|
public List<RobotSnapshotDto> Snapshots { get; init; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public record RobotSnapshotDto
|
||||||
|
{
|
||||||
|
public Guid Id { get; init; }
|
||||||
|
|
||||||
|
public DateTimeOffset DateCreated { get; init; }
|
||||||
|
|
||||||
|
public int TemplateRobotsCount { get; init; }
|
||||||
|
|
||||||
|
public int ScheduleRobotsCount { get; init; }
|
||||||
|
|
||||||
|
public int MaxRobots { get; init; }
|
||||||
|
}
|
||||||
|
}
|
||||||
15
PARR.Domain/DTOs/RobotSnapshotDTO/RobotSnapshotQuery.cs
Normal file
15
PARR.Domain/DTOs/RobotSnapshotDTO/RobotSnapshotQuery.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
namespace PARR.Domain.DTOs.RobotSnapshotDTO
|
||||||
|
{
|
||||||
|
public record RobotSnapshotQuery
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// IP робота
|
||||||
|
/// </summary>
|
||||||
|
public string? Ip { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Кол-во минут от текущего времени
|
||||||
|
/// </summary>
|
||||||
|
public int Minutes { get; init; }
|
||||||
|
}
|
||||||
|
}
|
||||||
25
PARR.Domain/DTOs/User/UserDto.cs
Normal file
25
PARR.Domain/DTOs/User/UserDto.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
namespace PARR.Domain.DTOs.User
|
||||||
|
{
|
||||||
|
//todo: Не делал маппингов
|
||||||
|
|
||||||
|
public record UserDto : UserBaseDto
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset DateCreated { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset? LastLogon { get; set; }
|
||||||
|
|
||||||
|
//todo:
|
||||||
|
//public List<RoleResponse>? Roles { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record UserBaseDto
|
||||||
|
{
|
||||||
|
public required string Ip { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user