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(); + } +}