Files
PnvPanel/backend/src/PnvPanel.Application/Admin/Support/ApproveRoleRequestCommandHandler.cs
T
Leonid Pershin b2ae358250
CI / Backend (build + test) (push) Successful in 1m22s
CI / Frontend (lint + typecheck + build) (push) Successful in 33s
Implement billing functionality and enhance role management
- Introduced billing capabilities, allowing users to request payments for subscription periods (3/6/12 months) with admin approval via Telegram.
- Updated role management to include a `BillingEnabled` property, preventing billing for admin roles.
- Enhanced the `CreateRoleCommand` and `UpdateRoleCommand` to accept billing parameters, ensuring proper handling during role creation and updates.
- Added new endpoints for billing management and integrated billing checks into VPN config creation to enforce payment requirements.
- Updated related services, models, and tests to support the new billing features, ensuring comprehensive coverage and functionality.
- Enhanced documentation to reflect the new billing processes and role management changes.
2026-07-19 01:38:16 +03:00

93 lines
2.8 KiB
C#

using Microsoft.EntityFrameworkCore;
using PnvPanel.Application.Auth;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Common.Messaging;
using PnvPanel.Application.Common.Models;
using PnvPanel.Application.Support;
using PnvPanel.Domain.Audit;
using PnvPanel.Domain.Support;
namespace PnvPanel.Application.Admin.Support;
public sealed class ApproveRoleRequestCommandHandler(
IAppDbContext dbContext,
IRoleService roleService,
IRealtimeNotifier notifier,
ITelegramNotifier telegramNotifier,
ICurrentUser currentUser
) : ICommandHandler<ApproveRoleRequestCommand, Result>
{
public async Task<Result> Handle(
ApproveRoleRequestCommand command,
CancellationToken cancellationToken
)
{
if (currentUser.UserId is not { } adminId)
return Result.Failure(AuthErrors.Unauthorized);
var ticket = await dbContext.SupportTickets.FirstOrDefaultAsync(
t => t.Id == command.TicketId,
cancellationToken
);
if (ticket is null)
return Result.Failure(SupportErrors.NotFound);
if (ticket.Type != TicketType.RoleRequest)
return Result.Failure(SupportErrors.NotRoleRequest);
if (ticket.Status != TicketStatus.Open)
return Result.Failure(SupportErrors.NotOpen);
Guid roleId;
if (ticket.RequestedRoleId is { } existingRoleId)
{
roleId = existingRoleId;
}
else
{
var createResult = await roleService.CreateRoleAsync(
ticket.ProposedRoleName!,
ticket.ProposedMaxConfigs!.Value,
ticket.ProposedMaxIpLimit!.Value,
billingEnabled: false,
cancellationToken
);
if (!createResult.IsSuccess)
return Result.Failure(createResult.Error);
roleId = createResult.Value.Id;
}
var assignResult = await roleService.ChangeUserRoleAsync(
ticket.UserId,
roleId,
cancellationToken
);
if (!assignResult.IsSuccess)
return assignResult;
ticket.Resolve();
dbContext.AuditLogs.Add(
AuditLog.Create(
adminId,
"RoleRequestApproved",
"SupportTicket",
ticket.Id.ToString(),
metadata: null,
AuditSource.Web
)
);
await notifier.NotifyTicketUpdatedAsync(ticket.Id, ticket.UserId, cancellationToken);
await telegramNotifier.NotifyUserAsync(
ticket.UserId,
"✅ Ваша заявка на роль одобрена.",
$"/support?ticket={ticket.Id}",
cancellationToken
);
return Result.Success();
}
}