- Updated various API endpoints to include response type annotations using .Produces<T>() for better documentation and type safety. - Enhanced activation, admin, user, config, and other endpoints to specify response types, improving clarity for frontend integration. - Added new DTOs for structured responses in authentication and Telegram-related endpoints. - Improved overall API schema generation to reflect these changes, ensuring consistency between backend and frontend types.
99 lines
4.4 KiB
C#
99 lines
4.4 KiB
C#
using PnvPanel.Api.Common;
|
|
using PnvPanel.Application.Common.Messaging;
|
|
using PnvPanel.Application.Configs;
|
|
using PnvPanel.Application.Configs.Create;
|
|
using PnvPanel.Application.Configs.Edit;
|
|
using PnvPanel.Application.Configs.GetConfigLink;
|
|
using PnvPanel.Application.Configs.GetMyConfigs;
|
|
using PnvPanel.Application.Configs.GetMySubscription;
|
|
using PnvPanel.Application.Configs.ListAvailableInbounds;
|
|
using PnvPanel.Application.Configs.Revoke;
|
|
using PnvPanel.Application.Configs.Rotate;
|
|
|
|
namespace PnvPanel.Api.Endpoints;
|
|
|
|
public static class ConfigEndpoints
|
|
{
|
|
public static IEndpointRouteBuilder MapConfigEndpoints(this IEndpointRouteBuilder app)
|
|
{
|
|
var group = app.MapGroup("/api").WithTags("Configs").RequireAuthorization();
|
|
|
|
group.MapGet("/inbounds/available", ListAvailableInbounds).Produces<IReadOnlyList<AvailableInboundDto>>();
|
|
group.MapGet("/configs", GetMyConfigs).Produces<GetMyConfigsResult>();
|
|
group.MapPost("/configs", CreateConfig).Produces<VpnConfigDto>();
|
|
group.MapPatch("/configs/{id:guid}", EditConfig).Produces<VpnConfigDto>();
|
|
group.MapPost("/configs/{id:guid}/rotate", RotateConfig).Produces<VpnConfigDto>();
|
|
group.MapDelete("/configs/{id:guid}", RevokeConfig).Produces(StatusCodes.Status204NoContent);
|
|
group.MapGet("/configs/{id:guid}/link", GetConfigLink).Produces<ConfigLinkResponseDto>();
|
|
group.MapGet("/subscription", GetMySubscription).Produces<MySubscriptionResponseDto>();
|
|
|
|
return app;
|
|
}
|
|
|
|
private static async Task<IResult> ListAvailableInbounds(ISender sender, CancellationToken cancellationToken)
|
|
{
|
|
var result = await sender.Send(new ListAvailableInboundsQuery(), cancellationToken);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> GetMyConfigs(ISender sender, CancellationToken cancellationToken)
|
|
{
|
|
var result = await sender.Send(new GetMyConfigsQuery(), cancellationToken);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> CreateConfig(CreateConfigBody body, ISender sender, CancellationToken cancellationToken)
|
|
{
|
|
var command = new CreateVpnConfigCommand(body.InboundId, body.Label, body.DeviceLimit);
|
|
var result = await sender.Send(command, cancellationToken);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> EditConfig(Guid id, EditConfigBody body, ISender sender, CancellationToken cancellationToken)
|
|
{
|
|
var command = new EditVpnConfigCommand(id, body.Label, body.DeviceLimit);
|
|
var result = await sender.Send(command, cancellationToken);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> RotateConfig(Guid id, ISender sender, CancellationToken cancellationToken)
|
|
{
|
|
var result = await sender.Send(new RotateVpnConfigCommand(id), cancellationToken);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> RevokeConfig(Guid id, ISender sender, CancellationToken cancellationToken)
|
|
{
|
|
var result = await sender.Send(new RevokeVpnConfigCommand(id), cancellationToken);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> GetConfigLink(Guid id, HttpRequest request, ISender sender, CancellationToken cancellationToken)
|
|
{
|
|
var result = await sender.Send(new GetConfigLinkQuery(id), cancellationToken);
|
|
if (!result.IsSuccess)
|
|
return result.ToHttpResult();
|
|
|
|
var subscriptionUrl = $"{request.Scheme}://{request.Host}/sub/{result.Value.SubscriptionToken}";
|
|
return Results.Ok(new ConfigLinkResponseDto(result.Value.ConnectionString, subscriptionUrl));
|
|
}
|
|
|
|
private static async Task<IResult> GetMySubscription(HttpRequest request, ISender sender, CancellationToken cancellationToken)
|
|
{
|
|
var result = await sender.Send(new GetMySubscriptionQuery(), cancellationToken);
|
|
if (!result.IsSuccess)
|
|
return result.ToHttpResult();
|
|
|
|
var subscriptionUrl = $"{request.Scheme}://{request.Host}/sub/{result.Value.SubscriptionToken}";
|
|
return Results.Ok(new MySubscriptionResponseDto(subscriptionUrl));
|
|
}
|
|
}
|
|
|
|
public sealed record CreateConfigBody(Guid InboundId, string? Label, int? DeviceLimit);
|
|
|
|
public sealed record EditConfigBody(string? Label, int? DeviceLimit);
|
|
|
|
public sealed record ConfigLinkResponseDto(string ConnectionString, string SubscriptionUrl);
|
|
|
|
public sealed record MySubscriptionResponseDto(string SubscriptionUrl);
|