Refactor project files for improved readability and structure
CI / Backend (build + test) (push) Successful in 1m18s
CI / Frontend (lint + typecheck + build) (push) Successful in 31s

- Cleaned up whitespace in Directory.Build.props and Directory.Packages.props for consistency.
- Reformatted project file references in PnvPanel.Api.csproj for better clarity.
- Enhanced code readability in various endpoint files by adjusting line breaks and indentation.
- Standardized method signatures and improved formatting in ResultExtensions and multiple endpoint classes for better maintainability.
This commit is contained in:
Leonid Pershin
2026-07-14 07:24:13 +03:00
parent 9d5424bb9c
commit df137ca5a7
285 changed files with 6911 additions and 2063 deletions
@@ -8,10 +8,16 @@ using PnvPanel.Domain.Configs;
namespace PnvPanel.Application.Configs.Create;
public sealed class CreateVpnConfigCommandHandler(
IAppDbContext dbContext, IIdentityService identityService, IXuiPanelGateway gateway, ICurrentUser currentUser)
: ICommandHandler<CreateVpnConfigCommand, Result<VpnConfigDto>>
IAppDbContext dbContext,
IIdentityService identityService,
IXuiPanelGateway gateway,
ICurrentUser currentUser
) : ICommandHandler<CreateVpnConfigCommand, Result<VpnConfigDto>>
{
public async Task<Result<VpnConfigDto>> Handle(CreateVpnConfigCommand command, CancellationToken cancellationToken)
public async Task<Result<VpnConfigDto>> Handle(
CreateVpnConfigCommand command,
CancellationToken cancellationToken
)
{
if (currentUser.UserId is not { } userId)
return Result.Failure<VpnConfigDto>(AuthErrors.Unauthorized);
@@ -20,7 +26,8 @@ public sealed class CreateVpnConfigCommandHandler(
if (profile is null)
return Result.Failure<VpnConfigDto>(AuthErrors.Unauthorized);
var inbound = await dbContext.Inbounds.AsNoTracking()
var inbound = await dbContext
.Inbounds.AsNoTracking()
.FirstOrDefaultAsync(i => i.Id == command.InboundId, cancellationToken);
if (inbound is null || !inbound.IsPublished)
@@ -29,19 +36,32 @@ public sealed class CreateVpnConfigCommandHandler(
if (!inbound.AllowedRoleIds.Contains(profile.RoleId))
return Result.Failure<VpnConfigDto>(ConfigErrors.InboundNotAllowedForRole);
var node = await dbContext.Nodes.AsNoTracking().FirstOrDefaultAsync(n => n.Id == inbound.NodeId, cancellationToken);
var node = await dbContext
.Nodes.AsNoTracking()
.FirstOrDefaultAsync(n => n.Id == inbound.NodeId, cancellationToken);
if (node is null || !node.IsEnabled)
return Result.Failure<VpnConfigDto>(ConfigErrors.NodeDisabled);
var config = VpnConfig.Create(userId, inbound.Id, inbound.Protocol, command.Label);
var reserveResult = await ReserveQuotaSlotAsync(userId, profile.MaxConfigs, config, cancellationToken);
var reserveResult = await ReserveQuotaSlotAsync(
userId,
profile.MaxConfigs,
config,
cancellationToken
);
if (!reserveResult.IsSuccess)
return Result.Failure<VpnConfigDto>(reserveResult.Error);
var addResult = await gateway.AddClientAsync(
node, inbound.RemoteInboundId, inbound.Protocol, config.ClientEmail,
config.Label ?? config.ClientEmail, profile.MaxIpLimit, cancellationToken);
node,
inbound.RemoteInboundId,
inbound.Protocol,
config.ClientEmail,
config.Label ?? config.ClientEmail,
profile.MaxIpLimit,
cancellationToken
);
if (!addResult.IsSuccess)
{
@@ -64,15 +84,26 @@ public sealed class CreateVpnConfigCommandHandler(
/// НЕ на время внешнего HTTP-вызова к 3x-ui — иначе рискуем держать соединение к БД открытым
/// на секунды под внешним I/O.
/// </summary>
private async Task<Result> ReserveQuotaSlotAsync(Guid userId, int maxConfigs, VpnConfig config, CancellationToken cancellationToken)
private async Task<Result> ReserveQuotaSlotAsync(
Guid userId,
int maxConfigs,
VpnConfig config,
CancellationToken cancellationToken
)
{
await using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken);
await using var transaction = await dbContext.Database.BeginTransactionAsync(
cancellationToken
);
await dbContext.Database.ExecuteSqlInterpolatedAsync(
$"SELECT pg_advisory_xact_lock(hashtext({userId.ToString()}))", cancellationToken);
$"SELECT pg_advisory_xact_lock(hashtext({userId.ToString()}))",
cancellationToken
);
var activeCount = await dbContext.VpnConfigs
.CountAsync(c => c.UserId == userId && c.Status == ConfigStatus.Active, cancellationToken);
var activeCount = await dbContext.VpnConfigs.CountAsync(
c => c.UserId == userId && c.Status == ConfigStatus.Active,
cancellationToken
);
if (maxConfigs != RoleQuota.Unlimited && activeCount >= maxConfigs)
{