- 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.
45 lines
2.1 KiB
C#
45 lines
2.1 KiB
C#
using System.Text;
|
|
using PnvPanel.Api.Common;
|
|
using PnvPanel.Application.Common.Messaging;
|
|
using PnvPanel.Application.Subscriptions;
|
|
|
|
namespace PnvPanel.Api.Endpoints;
|
|
|
|
public static class SubscriptionEndpoints
|
|
{
|
|
public static IEndpointRouteBuilder MapSubscriptionEndpoints(this IEndpointRouteBuilder app)
|
|
{
|
|
// Вне /api по дизайну (api-design.md) — публичный эндпоинт для VPN-клиентов.
|
|
app.MapGet("/sub/{token}", GetSubscription)
|
|
.WithTags("Subscription")
|
|
.RequireRateLimiting(RateLimiting.AuthPolicy)
|
|
.Produces<string>(StatusCodes.Status200OK, "text/plain")
|
|
.Produces(StatusCodes.Status404NotFound);
|
|
|
|
return app;
|
|
}
|
|
|
|
private static async Task<IResult> GetSubscription(string token, HttpResponse response, ISender sender, CancellationToken cancellationToken)
|
|
{
|
|
// Токен — либо AppUser.SubscriptionToken (агрегированная подписка), либо VpnConfig.SubscriptionToken
|
|
// (один конфиг). Пробуем пользовательский токен первым.
|
|
var userResult = await sender.Send(new GetUserSubscriptionQuery(token), cancellationToken);
|
|
var result = userResult.IsSuccess ? userResult : await sender.Send(new GetConfigSubscriptionQuery(token), cancellationToken);
|
|
|
|
if (!result.IsSuccess)
|
|
return Results.NotFound();
|
|
|
|
var body = string.Join('\n', result.Value.ConnectionStrings);
|
|
var base64Body = Convert.ToBase64String(Encoding.UTF8.GetBytes(body));
|
|
|
|
var total = result.Value.UsedUpBytes + result.Value.UsedDownBytes;
|
|
var expire = result.Value.ExpiresAt is { } exp ? exp.ToUnixTimeSeconds().ToString() : "0";
|
|
response.Headers.Append(
|
|
"Subscription-Userinfo",
|
|
$"upload={result.Value.UsedUpBytes}; download={result.Value.UsedDownBytes}; total={total}; expire={expire}");
|
|
response.Headers.Append("Profile-Update-Interval", "12");
|
|
|
|
return Results.Text(base64Body, "text/plain; charset=utf-8");
|
|
}
|
|
}
|