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,15 @@
|
||||
using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Activation;
|
||||
|
||||
public static class ActivationErrors
|
||||
{
|
||||
public static readonly Error AlreadyPending =
|
||||
Error.Conflict("Activation.AlreadyPending", "У вас уже есть необработанный запрос на активацию.");
|
||||
|
||||
public static readonly Error NotFound =
|
||||
Error.NotFound("Activation.NotFound", "Запрос на активацию не найден.");
|
||||
|
||||
public static readonly Error AlreadyDecided =
|
||||
Error.Conflict("Activation.AlreadyDecided", "Запрос на активацию уже обработан.");
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace PnvPanel.Application.Activation;
|
||||
|
||||
public sealed record ActivationRequestDto(Guid Id, string? Comment, DateTimeOffset CreatedAt);
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace PnvPanel.Application.Activation;
|
||||
|
||||
public sealed record ActivationStatusDto(bool IsActivated, ActivationRequestDto? PendingRequest);
|
||||
@@ -0,0 +1,6 @@
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Activation;
|
||||
|
||||
public sealed record GetActivationStatusQuery : IQuery<Result<ActivationStatusDto>>;
|
||||
@@ -0,0 +1,29 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PnvPanel.Application.Auth;
|
||||
using PnvPanel.Application.Common.Interfaces;
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
using PnvPanel.Application.Common.Models;
|
||||
using PnvPanel.Domain.Activation;
|
||||
|
||||
namespace PnvPanel.Application.Activation;
|
||||
|
||||
public sealed class GetActivationStatusQueryHandler(IIdentityService identityService, IAppDbContext dbContext, ICurrentUser currentUser)
|
||||
: IQueryHandler<GetActivationStatusQuery, Result<ActivationStatusDto>>
|
||||
{
|
||||
public async Task<Result<ActivationStatusDto>> Handle(GetActivationStatusQuery query, CancellationToken cancellationToken)
|
||||
{
|
||||
if (currentUser.UserId is not { } userId)
|
||||
return Result.Failure<ActivationStatusDto>(AuthErrors.Unauthorized);
|
||||
|
||||
var profile = await identityService.GetProfileAsync(userId, cancellationToken);
|
||||
if (profile is null)
|
||||
return Result.Failure<ActivationStatusDto>(AuthErrors.Unauthorized);
|
||||
|
||||
var pending = await dbContext.ActivationRequests
|
||||
.Where(r => r.UserId == userId && r.Status == ActivationStatus.Pending)
|
||||
.Select(r => new ActivationRequestDto(r.Id, r.Comment, r.CreatedAt))
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
return Result.Success(new ActivationStatusDto(profile.IsActivated, pending));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
using PnvPanel.Application.Common.Models;
|
||||
|
||||
namespace PnvPanel.Application.Activation;
|
||||
|
||||
public sealed record RequestActivationCommand(string? Comment) : ICommand<Result<ActivationRequestDto>>;
|
||||
@@ -0,0 +1,29 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PnvPanel.Application.Auth;
|
||||
using PnvPanel.Application.Common.Interfaces;
|
||||
using PnvPanel.Application.Common.Messaging;
|
||||
using PnvPanel.Application.Common.Models;
|
||||
using PnvPanel.Domain.Activation;
|
||||
|
||||
namespace PnvPanel.Application.Activation;
|
||||
|
||||
public sealed class RequestActivationCommandHandler(IAppDbContext dbContext, ICurrentUser currentUser)
|
||||
: ICommandHandler<RequestActivationCommand, Result<ActivationRequestDto>>
|
||||
{
|
||||
public async Task<Result<ActivationRequestDto>> Handle(RequestActivationCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
if (currentUser.UserId is not { } userId)
|
||||
return Result.Failure<ActivationRequestDto>(AuthErrors.Unauthorized);
|
||||
|
||||
var hasPending = await dbContext.ActivationRequests
|
||||
.AnyAsync(r => r.UserId == userId && r.Status == ActivationStatus.Pending, cancellationToken);
|
||||
|
||||
if (hasPending)
|
||||
return Result.Failure<ActivationRequestDto>(ActivationErrors.AlreadyPending);
|
||||
|
||||
var request = ActivationRequest.Create(userId, command.Comment);
|
||||
dbContext.ActivationRequests.Add(request);
|
||||
|
||||
return Result.Success(new ActivationRequestDto(request.Id, request.Comment, request.CreatedAt));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace PnvPanel.Application.Activation;
|
||||
|
||||
public sealed class RequestActivationCommandValidator : AbstractValidator<RequestActivationCommand>
|
||||
{
|
||||
public RequestActivationCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.Comment).MaximumLength(500);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user