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,53 @@
|
||||
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.Configs;
|
||||
|
||||
namespace PnvPanel.Application.Configs.Rotate;
|
||||
|
||||
public sealed class RotateVpnConfigCommandHandler(IAppDbContext dbContext, IXuiPanelGateway gateway, ICurrentUser currentUser)
|
||||
: ICommandHandler<RotateVpnConfigCommand, Result<VpnConfigDto>>
|
||||
{
|
||||
public async Task<Result<VpnConfigDto>> Handle(RotateVpnConfigCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
if (currentUser.UserId is not { } userId)
|
||||
return Result.Failure<VpnConfigDto>(AuthErrors.Unauthorized);
|
||||
|
||||
var config = await dbContext.VpnConfigs
|
||||
.FirstOrDefaultAsync(c => c.Id == command.ConfigId && c.UserId == userId, cancellationToken);
|
||||
if (config is null)
|
||||
return Result.Failure<VpnConfigDto>(ConfigErrors.NotFound);
|
||||
|
||||
if (config.Status != ConfigStatus.Active)
|
||||
return Result.Failure<VpnConfigDto>(ConfigErrors.NotFound);
|
||||
|
||||
var inbound = await dbContext.Inbounds.AsNoTracking()
|
||||
.FirstOrDefaultAsync(i => i.Id == config.InboundId, cancellationToken);
|
||||
if (inbound is null)
|
||||
return Result.Failure<VpnConfigDto>(ConfigErrors.InboundNotAvailable);
|
||||
|
||||
var node = await dbContext.Nodes.AsNoTracking().FirstOrDefaultAsync(n => n.Id == inbound.NodeId, cancellationToken);
|
||||
if (node is null)
|
||||
return Result.Failure<VpnConfigDto>(ConfigErrors.NodeDisabled);
|
||||
|
||||
var newClientEmail = VpnConfig.GenerateClientEmail(userId);
|
||||
var addResult = await gateway.AddClientAsync(
|
||||
node, inbound.RemoteInboundId, config.Protocol, newClientEmail,
|
||||
config.Label ?? newClientEmail, config.DeviceLimit, cancellationToken);
|
||||
|
||||
if (!addResult.IsSuccess)
|
||||
return Result.Failure<VpnConfigDto>(addResult.Error);
|
||||
|
||||
var oldClientExternalId = config.ClientExternalId;
|
||||
config.Rotate(newClientEmail, addResult.Value);
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// Старого клиента удаляем ПОСЛЕ коммита нового состояния: если удаление не выйдет,
|
||||
// у пользователя просто останется лишний нерабочий-для-него клиент в панели — не критично.
|
||||
await gateway.RemoveClientAsync(node, inbound.RemoteInboundId, oldClientExternalId, config.Protocol, cancellationToken);
|
||||
|
||||
return Result.Success(VpnConfigDto.FromDomain(config, inbound));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user