Merge branch 'dev' of http://gitlab.dvgd.oao.rzd/devptk/parr/parr_api into dev
This commit is contained in:
@@ -258,6 +258,7 @@
|
||||
|
||||
public static class StatRobotSnapshot
|
||||
{
|
||||
public const string GetAll = 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
|
||||
{
|
||||
public record StatRobotSnapshotItemResponse
|
||||
{
|
||||
public required UserBaseResponse Robot { get; init; }
|
||||
|
||||
public List<StatRobotSnapshotResponse> Snapshots { get; init; } = new();
|
||||
}
|
||||
|
||||
public record StatRobotSnapshotResponse
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
|
||||
@@ -11,7 +18,5 @@
|
||||
public int ScheduleRobotsCount { 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 PARR.API.Contracts.V1;
|
||||
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.Statistics;
|
||||
using PARR.API.Controllers.V1.Base;
|
||||
@@ -13,7 +14,7 @@ using PARR.Domain.DTOs.RobotSnapshotDTO;
|
||||
|
||||
namespace PARR.API.Controllers.V1.Statistics
|
||||
{
|
||||
[Authorize(Roles = ParrRoles.Administrator.Role)]
|
||||
[Authorize]
|
||||
public class StatRobotSnapshotController : BaseApiController
|
||||
{
|
||||
private readonly IRobotSnapshotService robotSnapshotService;
|
||||
@@ -31,6 +32,28 @@ namespace PARR.API.Controllers.V1.Statistics
|
||||
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>
|
||||
/// Отправить снапшот роботов.
|
||||
/// Доступ только с ролью "Робот ЕСПП"
|
||||
|
||||
@@ -9,6 +9,7 @@ using PARR.Domain.DTOs.RobotSnapshotDTO;
|
||||
using PARR.Domain.DTOs.RobotTask;
|
||||
using PARR.Domain.DTOs.Shortcode;
|
||||
using PARR.Domain.DTOs.TaskDTO;
|
||||
using PARR.Domain.DTOs.User;
|
||||
using PARR.Domain.DTOs.Workload;
|
||||
using PARR.Domain.Entities;
|
||||
using PARR.Domain.Entities.Base.History;
|
||||
@@ -312,6 +313,8 @@ namespace PARR.API.MappingProfiles
|
||||
|
||||
CreateMap<UserCache, UserProfileResponse>();
|
||||
|
||||
CreateMap<UserBaseDto, UserBaseResponse>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Order
|
||||
@@ -486,8 +489,13 @@ namespace PARR.API.MappingProfiles
|
||||
|
||||
#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.Queries;
|
||||
using PARR.Domain.Common.Pagination;
|
||||
using PARR.Domain.DTOs.RobotSnapshotDTO;
|
||||
using PARR.Domain.Entities.Job;
|
||||
|
||||
namespace PARR.API.MappingProfiles
|
||||
@@ -45,6 +46,8 @@ namespace PARR.API.MappingProfiles
|
||||
CreateMap<RelationshipFilterRequest, JobRelationshipFilter>();
|
||||
|
||||
#endregion
|
||||
|
||||
CreateMap<StatRobotSnapshotQuery, RobotSnapshotQuery>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace PARR.Core.Infrastructure.Mapping.RobotSnapshot
|
||||
{
|
||||
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
|
||||
{
|
||||
Task<RobotSnapshotItem> CreateAsync(CreateRobotSnapshot robotSnapshot);
|
||||
Task<List<RobotSnapshotItemDto>> GetAsync(RobotSnapshotQuery queryDto);
|
||||
|
||||
Task<RobotSnapshotItemDto> CreateAsync(CreateRobotSnapshot robotSnapshot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PARR.Core.Repositories.Interfaces;
|
||||
using PARR.Core.Repositories.Interfaces.RobotRepositories;
|
||||
using PARR.Domain.DTOs.RobotSnapshotDTO;
|
||||
using PARR.Domain.DTOs.User;
|
||||
using PARR.Domain.Entities.RobotEntities;
|
||||
using PARR.Domain.Exceptions;
|
||||
|
||||
@@ -9,19 +12,63 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
||||
internal class RobotSnapshotService : IRobotSnapshotService
|
||||
{
|
||||
private readonly IRobotSnapshotRepository robotSnapshotRepository;
|
||||
private readonly IUserRepository userRepository;
|
||||
private readonly IMapper mapper;
|
||||
|
||||
public RobotSnapshotService(
|
||||
IRobotSnapshotRepository robotSnapshotRepository,
|
||||
IUserRepository userRepository,
|
||||
IMapper mapper
|
||||
)
|
||||
{
|
||||
this.robotSnapshotRepository = robotSnapshotRepository;
|
||||
this.userRepository = userRepository;
|
||||
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
|
||||
{
|
||||
@@ -38,7 +85,16 @@ namespace PARR.Core.Services.RobotSnapshotServices
|
||||
if (!createdResult || !commitResult)
|
||||
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