Implement activation checks across various commands and queries
- Introduced `IRequiresActivation` interface to enforce activation requirements for multiple commands and queries, ensuring that only activated users can create, edit, or access configurations, news, and applications. - Updated the `RequireActivationBehavior` to handle activation checks uniformly, returning appropriate errors for unauthenticated or inactive users. - Enhanced error handling by adding `NotActivated` error to provide clear feedback for users attempting to access restricted features. - Updated documentation to reflect the new activation requirements and their implications on user access and functionality.
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
using PnvPanel.Application.Auth;
|
||||
using PnvPanel.Application.Common.Interfaces;
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Common.Behaviors;
|
||||
|
||||
/// <summary>
|
||||
/// Единая точка проверки активации для запросов, реализующих <see cref="IRequiresActivation"/> —
|
||||
/// вместо разбросанных if(!profile.IsActivated) по хендлерам. Применяется только к запросам с этим
|
||||
/// маркером (generic-ограничение), остальные проходят мимо.
|
||||
/// </summary>
|
||||
public sealed class RequireActivationBehavior<TRequest, TResponse>(ICurrentUser currentUser, IIdentityService identityService)
|
||||
: IPipelineBehavior<TRequest, TResponse>
|
||||
where TRequest : IRequiresActivation
|
||||
where TResponse : Result
|
||||
{
|
||||
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
|
||||
{
|
||||
if (currentUser.UserId is not { } userId)
|
||||
return ResultFailureFactory.Create<TResponse>(AuthErrors.Unauthorized);
|
||||
|
||||
var profile = await identityService.GetProfileAsync(userId, cancellationToken);
|
||||
if (profile is null)
|
||||
return ResultFailureFactory.Create<TResponse>(AuthErrors.Unauthorized);
|
||||
|
||||
if (!profile.IsActivated)
|
||||
return ResultFailureFactory.Create<TResponse>(AuthErrors.NotActivated);
|
||||
|
||||
return await next();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Common.Behaviors;
|
||||
|
||||
/// <summary>Строит Result/Result<T> failure-ответ через reflection — общий хелпер для generic pipeline behaviors.</summary>
|
||||
internal static class ResultFailureFactory
|
||||
{
|
||||
public static TResponse Create<TResponse>(Error error) where TResponse : Result
|
||||
{
|
||||
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])!;
|
||||
}
|
||||
}
|
||||
@@ -27,19 +27,6 @@ public sealed class ValidationBehavior<TRequest, TResponse>(IEnumerable<IValidat
|
||||
"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])!;
|
||||
return ResultFailureFactory.Create<TResponse>(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace PnvPanel.Application.Common.Messaging;
|
||||
|
||||
/// <summary>Маркер: запрос доступен только активированным пользователям — проверяется RequireActivationBehavior.</summary>
|
||||
public interface IRequiresActivation;
|
||||
Reference in New Issue
Block a user