Enhance documentation with new features: added dark/light/system theme support, instructions page, and application catalog. Updated API and domain model for app management and automatic migrations on startup. Improved frontend structure with new routes and features for user instructions and app management.
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
|
||||
namespace PnvPanel.Application.Common.Behaviors;
|
||||
|
||||
public sealed class LoggingBehavior<TRequest, TResponse>(ILogger<LoggingBehavior<TRequest, TResponse>> logger)
|
||||
: IPipelineBehavior<TRequest, TResponse>
|
||||
where TRequest : notnull
|
||||
{
|
||||
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
|
||||
{
|
||||
var requestName = typeof(TRequest).Name;
|
||||
logger.LogInformation("Обработка {RequestName}", requestName);
|
||||
|
||||
var response = await next();
|
||||
|
||||
logger.LogInformation("Обработан {RequestName}", requestName);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using PnvPanel.Application.Common.Interfaces;
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
|
||||
namespace PnvPanel.Application.Common.Behaviors;
|
||||
|
||||
/// <summary>
|
||||
/// Коммитит изменения после успешного выполнения команды. Применяется автоматически только
|
||||
/// к запросам, реализующим <see cref="ICommand{TResponse}"/> — благодаря generic-ограничению
|
||||
/// DI-контейнер не сможет сконструировать это поведение для запросов (IQuery).
|
||||
/// </summary>
|
||||
public sealed class UnitOfWorkBehavior<TRequest, TResponse>(IAppDbContext dbContext)
|
||||
: IPipelineBehavior<TRequest, TResponse>
|
||||
where TRequest : ICommand<TResponse>
|
||||
{
|
||||
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await next();
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using FluentValidation;
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Common.Behaviors;
|
||||
|
||||
public sealed class ValidationBehavior<TRequest, TResponse>(IEnumerable<IValidator<TRequest>> validators)
|
||||
: IPipelineBehavior<TRequest, TResponse>
|
||||
where TRequest : notnull
|
||||
where TResponse : Result
|
||||
{
|
||||
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!validators.Any())
|
||||
return await next();
|
||||
|
||||
var context = new ValidationContext<TRequest>(request);
|
||||
var failures = validators
|
||||
.Select(v => v.Validate(context))
|
||||
.SelectMany(r => r.Errors)
|
||||
.ToList();
|
||||
|
||||
if (failures.Count == 0)
|
||||
return await next();
|
||||
|
||||
var error = Error.Validation(
|
||||
"Validation.Failed",
|
||||
string.Join("; ", failures.Select(f => f.ErrorMessage)));
|
||||
|
||||
return CreateFailure(error);
|
||||
}
|
||||
|
||||
private static TResponse CreateFailure(Error error)
|
||||
{
|
||||
if (typeof(TResponse) == typeof(Result))
|
||||
return (TResponse)(object)Result.Failure(error);
|
||||
|
||||
var valueType = typeof(TResponse).GetGenericArguments()[0];
|
||||
var method = typeof(Result)
|
||||
.GetMethod(nameof(Result.Failure), 1, [typeof(Error)])!
|
||||
.MakeGenericMethod(valueType);
|
||||
|
||||
return (TResponse)method.Invoke(null, [error])!;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user