diff --git a/PARR.API/Contracts/V1/ApiRoutes.cs b/PARR.API/Contracts/V1/ApiRoutes.cs
index 7ae1abb6..a225fdb6 100644
--- a/PARR.API/Contracts/V1/ApiRoutes.cs
+++ b/PARR.API/Contracts/V1/ApiRoutes.cs
@@ -73,6 +73,11 @@
public const string getParam = "{id}";
}
+ public static class TemplateHistory
+ {
+ public const string GetAll = Base + "/template-histories/";
+ }
+
public static class TemplateScheduleEspp
{
public const string Get = Base + "/templates/" + templateId + "/schedule-esppid";
diff --git a/PARR.API/Contracts/V1/Requests/Queries/TemplateHistoryQuery.cs b/PARR.API/Contracts/V1/Requests/Queries/TemplateHistoryQuery.cs
new file mode 100644
index 00000000..994b2578
--- /dev/null
+++ b/PARR.API/Contracts/V1/Requests/Queries/TemplateHistoryQuery.cs
@@ -0,0 +1,22 @@
+using PARR.Constants;
+
+namespace PARR.API.Contracts.V1.Requests.Queries
+{
+ public class TemplateHistoryQuery
+ {
+ ///
+ /// ИД шаблона
+ ///
+ public Guid? TemplateId { get; set; }
+
+ ///
+ /// IP инициатора
+ ///
+ public string? InitiatorIp { get; set; }
+
+ ///
+ /// ИД компонента ПАРР
+ ///
+ public ParrComponentsEnum? ParrComponentId { get; set; }
+ }
+}
diff --git a/PARR.API/Contracts/V1/Responses/HistoryInitiatorResponse.cs b/PARR.API/Contracts/V1/Responses/HistoryInitiatorResponse.cs
new file mode 100644
index 00000000..852cf861
--- /dev/null
+++ b/PARR.API/Contracts/V1/Responses/HistoryInitiatorResponse.cs
@@ -0,0 +1,12 @@
+namespace PARR.API.Contracts.V1.Responses
+{
+ public class HistoryInitiatorResponse
+ {
+ public string? Ip { get; set; }
+ public string? Comment { get; set; }
+ public int? ParrComponentId { get; set; }
+
+ public ParrComponentResponse? ParrComponent { get; set; }
+ public UserBaseResponse? User { get; set; }
+ }
+}
diff --git a/PARR.API/Contracts/V1/Responses/ParrComponentResponse.cs b/PARR.API/Contracts/V1/Responses/ParrComponentResponse.cs
new file mode 100644
index 00000000..fbcbf35c
--- /dev/null
+++ b/PARR.API/Contracts/V1/Responses/ParrComponentResponse.cs
@@ -0,0 +1,9 @@
+namespace PARR.API.Contracts.V1.Responses
+{
+ public class ParrComponentResponse
+ {
+ public int Id { get; set; }
+ public required string Name { get; set; }
+ public required string Description { get; set; }
+ }
+}
diff --git a/PARR.API/Contracts/V1/Responses/TemplateHistoryResponse.cs b/PARR.API/Contracts/V1/Responses/TemplateHistoryResponse.cs
new file mode 100644
index 00000000..f9baf4dd
--- /dev/null
+++ b/PARR.API/Contracts/V1/Responses/TemplateHistoryResponse.cs
@@ -0,0 +1,25 @@
+namespace PARR.API.Contracts.V1.Responses
+{
+ public class TemplateHistoryResponse
+ {
+ public Guid Id { get; set; }
+
+ public Guid TemplateId { get; set; }
+
+ public DateTimeOffset DateAddedToHistory { get; set; }
+
+ public DateTimeOffset? DateModified { get; set; }
+
+ public required string Name { get; set; }
+
+ public bool IsActiveTemplate { get; set; }
+
+ public bool IsActiveSchedule { get; set; }
+
+ public DateTimeOffset? LastRun { get; set; }
+
+ public DateTimeOffset NextRun { get; set; }
+
+ public HistoryInitiatorResponse? Initiator { get; set; }
+ }
+}
diff --git a/PARR.API/Controllers/V1/TemplateHistoryController.cs b/PARR.API/Controllers/V1/TemplateHistoryController.cs
new file mode 100644
index 00000000..f88a046d
--- /dev/null
+++ b/PARR.API/Controllers/V1/TemplateHistoryController.cs
@@ -0,0 +1,70 @@
+using AutoMapper;
+using Microsoft.AspNetCore.Authorization;
+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.Constants;
+using PARR.DAL.DomainModels;
+using PARR.DAL.Models;
+using PARR.DAL.Services.Interfaces;
+
+namespace PARR.API.Controllers.V1
+{
+ ///
+ /// История изменения шаблонов
+ ///
+ [Authorize(Roles = ParrRoles.Administrator.Role)]
+ public class TemplateHistoryController : BaseApiController
+ {
+ private readonly IMapper mapper;
+ private readonly ITemplateHistoryService templateHistoryService;
+
+ public TemplateHistoryController(
+ IMapper mapper,
+ ITemplateHistoryService templateHistoryService
+ )
+ {
+ this.mapper = mapper;
+ this.templateHistoryService = templateHistoryService;
+ }
+
+
+ ///
+ /// Получить историю изменения шаблонов постранично
+ ///
+ ///
+ [HttpGet(ApiRoutes.TemplateHistory.GetAll)]
+ public async Task GetAll([FromQuery] PaginationQuery paginationQuery, [FromQuery] TemplateHistoryQuery requestQuery)
+ {
+ var paginationFilter = mapper.Map(paginationQuery);
+
+ IQueryable query = templateHistoryService.Get()
+ .OrderByDescending(t => t.DateAddedToHistory);
+
+ if (requestQuery.TemplateId.HasValue)
+ query = query.Where(t => t.ParentId == requestQuery.TemplateId.Value);
+
+ if (!string.IsNullOrEmpty(requestQuery.InitiatorIp))
+ query = query.Where(t => t.InitiatorIp == requestQuery.InitiatorIp);
+
+ if (requestQuery.ParrComponentId != null)
+ query = query.Where(t => t.InitiatorParrComponentId == requestQuery.ParrComponentId);
+
+ var history = await templateHistoryService.GetPage(query, paginationFilter).ToListAsync();
+
+ if (!history.Any())
+ return NoContent();
+
+ var historyResponse = mapper.Map>(history);
+ var paginationResponse = new PagedResponse(historyResponse, true).GetPaginatedProps(paginationFilter, query);
+
+ return Ok(paginationResponse);
+ }
+
+ }
+}
diff --git a/PARR.API/MappingProfiles/DomainToResponseProfile.cs b/PARR.API/MappingProfiles/DomainToResponseProfile.cs
index 378e0f5d..c9dd6fa2 100644
--- a/PARR.API/MappingProfiles/DomainToResponseProfile.cs
+++ b/PARR.API/MappingProfiles/DomainToResponseProfile.cs
@@ -2,6 +2,7 @@
using PARR.API.Authentication.Models;
using PARR.API.Contracts.V1.Responses;
using PARR.API.MappingProfiles.Resolvers;
+using PARR.Common.Domain;
using PARR.Constants.Shortcode;
using PARR.DAL.DomainModels;
using PARR.DAL.Extensions;
@@ -300,6 +301,29 @@ namespace PARR.API.MappingProfiles
CreateMap();
+
+ #region TemplateHistory
+
+ CreateMap()
+ .ForMember(d => d.TemplateId, o => o.MapFrom(s => s.ParentId))
+ .ForMember(d => d.Initiator, o => o.MapFrom(s => s));
+
+ #endregion
+
+
+ #region Initiator
+
+ CreateMap()
+ .ForMember(d => d.Ip, o => o.MapFrom(s => s.InitiatorIp))
+ .ForMember(d => d.Comment, o => o.MapFrom(s => s.InitiatorComment))
+ .ForMember(d => d.ParrComponentId, o => o.MapFrom(s => s.InitiatorParrComponentId))
+ .ForMember(d => d.ParrComponent, o => o.MapFrom())
+ .ForMember(d => d.User, o => o.MapFrom());
+
+ #endregion
+
}
}
+
+
}
diff --git a/PARR.API/MappingProfiles/Resolvers/HistoryInitiatorParrComponentResolver.cs b/PARR.API/MappingProfiles/Resolvers/HistoryInitiatorParrComponentResolver.cs
new file mode 100644
index 00000000..c7d7e421
--- /dev/null
+++ b/PARR.API/MappingProfiles/Resolvers/HistoryInitiatorParrComponentResolver.cs
@@ -0,0 +1,28 @@
+using AutoMapper;
+using Microsoft.EntityFrameworkCore;
+using PARR.API.Contracts.V1.Responses;
+using PARR.Common.Domain;
+using PARR.DAL.Services.Interfaces;
+
+namespace PARR.API.MappingProfiles.Resolvers
+{
+ public class HistoryInitiatorParrComponentResolver : IValueResolver
+ {
+ private readonly IParrComponentService parrComponentService;
+
+ public HistoryInitiatorParrComponentResolver(IParrComponentService parrComponentService)
+ {
+ this.parrComponentService = parrComponentService;
+ }
+
+ public ParrComponentResponse? Resolve(IHistoryInitiator source, HistoryInitiatorResponse destination, ParrComponentResponse? destMember, ResolutionContext context)
+ {
+ var component = parrComponentService.Get().FirstOrDefaultAsync(t => t.Id == source.InitiatorParrComponentId).GetAwaiter().GetResult();
+
+ if (component == null)
+ return null;
+
+ return new ParrComponentResponse { Description = component.Description, Name = component.Name, Id = (int)component.Id };
+ }
+ }
+}
diff --git a/PARR.API/MappingProfiles/Resolvers/HistoryInitiatorUserResolver.cs b/PARR.API/MappingProfiles/Resolvers/HistoryInitiatorUserResolver.cs
new file mode 100644
index 00000000..0abd76e4
--- /dev/null
+++ b/PARR.API/MappingProfiles/Resolvers/HistoryInitiatorUserResolver.cs
@@ -0,0 +1,28 @@
+using AutoMapper;
+using Microsoft.EntityFrameworkCore;
+using PARR.API.Contracts.V1.Responses;
+using PARR.Common.Domain;
+using PARR.DAL.Services.Interfaces;
+
+namespace PARR.API.MappingProfiles.Resolvers
+{
+ public class HistoryInitiatorUserResolver : IValueResolver
+ {
+ private readonly IUserService userService;
+
+ public HistoryInitiatorUserResolver(IUserService userService)
+ {
+ this.userService = userService;
+ }
+
+ public UserBaseResponse? Resolve(IHistoryInitiator source, HistoryInitiatorResponse destination, UserBaseResponse? destMember, ResolutionContext context)
+ {
+ var user = userService.Get().FirstOrDefaultAsync(t => t.Ip == source.InitiatorIp).GetAwaiter().GetResult();
+
+ if (user == null)
+ return null;
+
+ return new UserBaseResponse { Ip = user.Ip, Description = user.Description ?? string.Empty, Name = user.Name };
+ }
+ }
+}
diff --git a/PARR.DAL/ParrDalInstaller.cs b/PARR.DAL/ParrDalInstaller.cs
index ea0f7d3b..f2df4ba1 100644
--- a/PARR.DAL/ParrDalInstaller.cs
+++ b/PARR.DAL/ParrDalInstaller.cs
@@ -87,6 +87,7 @@ namespace PARR.DAL
services.AddTransient();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
// TransformServices
diff --git a/PARR.DAL/Services/Implementations/ParrComponentService.cs b/PARR.DAL/Services/Implementations/ParrComponentService.cs
new file mode 100644
index 00000000..d4f7f8c7
--- /dev/null
+++ b/PARR.DAL/Services/Implementations/ParrComponentService.cs
@@ -0,0 +1,21 @@
+using PARR.DAL.Context;
+using PARR.DAL.Models;
+using PARR.DAL.Services.Interfaces;
+
+namespace PARR.DAL.Services.Implementations
+{
+ internal class ParrComponentService : IParrComponentService
+ {
+ private readonly DataContext dataContext;
+
+ public ParrComponentService(DataContext dataContext)
+ {
+ this.dataContext = dataContext;
+ }
+
+ public IQueryable Get()
+ {
+ return dataContext.ParrComponents;
+ }
+ }
+}
diff --git a/PARR.DAL/Services/Interfaces/IParrComponentService.cs b/PARR.DAL/Services/Interfaces/IParrComponentService.cs
new file mode 100644
index 00000000..088d5b61
--- /dev/null
+++ b/PARR.DAL/Services/Interfaces/IParrComponentService.cs
@@ -0,0 +1,9 @@
+using PARR.DAL.Models;
+
+namespace PARR.DAL.Services.Interfaces
+{
+ public interface IParrComponentService
+ {
+ IQueryable Get();
+ }
+}