126 lines
5.6 KiB
C#
126 lines
5.6 KiB
C#
using Knot.Contracts.Settings.Application.Abstractions;
|
|
using Knot.Contracts.Settings.Application.DTOs;
|
|
using Knot.Modules.Admin.Application.Admin.Commands;
|
|
using Knot.Modules.Admin.Application.Admin.Commands.TestKlipy;
|
|
using Knot.Modules.Admin.Application.Admin.Queries;
|
|
using MediatR;
|
|
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Routing;
|
|
|
|
namespace Knot.Host.Presentation.Endpoints;
|
|
|
|
public record KlipyTestDto(string ApiKey, string AppName);
|
|
public record ResetPasswordRequest(string NewPassword);
|
|
|
|
public static class AdminEndpoints
|
|
{
|
|
public static void MapAdminEndpoints(this WebApplication app)
|
|
{
|
|
var group = app.MapGroup("api/admin"); // Middleware handles auth
|
|
|
|
group.MapGet("settings", async (ISender sender, CancellationToken ct) =>
|
|
{
|
|
var result = await sender.Send(new GetSettingsQuery(), ct);
|
|
return Results.Ok(result.Value);
|
|
});
|
|
|
|
group.MapPut("settings", async ([FromBody] SystemSettingsDto settings, ISender sender, CancellationToken ct) =>
|
|
{
|
|
var result = await sender.Send(new UpdateSettingsCommand(settings), ct);
|
|
return Results.Ok(result.Value);
|
|
});
|
|
|
|
group.MapPost("settings/test-klipy", async ([FromBody] KlipyTestDto dto, ISender sender, CancellationToken ct) =>
|
|
{
|
|
var result = await sender.Send(new TestKlipyConnectionCommand(dto.ApiKey, dto.AppName), ct);
|
|
return result.IsSuccess ? Results.Ok(new { success = true }) : Results.BadRequest(new { error = result.Error.Description });
|
|
});
|
|
|
|
group.MapGet("dashboard", async (ISender sender, CancellationToken ct) =>
|
|
{
|
|
var result = await sender.Send(new GetDashboardStatsQuery(), ct);
|
|
return Results.Ok(result.Value);
|
|
});
|
|
|
|
group.MapPost("users/{userId:guid}/reset-password", async ([FromRoute] Guid userId, [FromBody] ResetPasswordRequest dto, ISender sender, CancellationToken ct) =>
|
|
{
|
|
var result = await sender.Send(new ResetUserPasswordCommand(userId, dto.NewPassword), ct);
|
|
if (result.IsFailure)
|
|
{
|
|
if (result.Error.Code == "User.NotFound") return Results.NotFound(new { error = "User not found" });
|
|
return Results.BadRequest(new { error = result.Error.Description });
|
|
}
|
|
return Results.Ok(result.Value);
|
|
});
|
|
|
|
group.MapPost("users/{userId:guid}/ban", async ([FromRoute] Guid userId, ISender sender, CancellationToken ct) =>
|
|
{
|
|
var result = await sender.Send(new BanUserCommand(userId), ct);
|
|
return result.IsSuccess ? Results.Ok() : Results.BadRequest(new { error = result.Error.Description });
|
|
});
|
|
|
|
group.MapPost("users/{userId:guid}/unban", async ([FromRoute] Guid userId, ISender sender, CancellationToken ct) =>
|
|
{
|
|
var result = await sender.Send(new UnbanUserCommand(userId), ct);
|
|
return result.IsSuccess ? Results.Ok() : Results.BadRequest(new { error = result.Error.Description });
|
|
});
|
|
|
|
group.MapGet("users", async (ISender sender, [FromQuery] string? query, CancellationToken ct = default) =>
|
|
{
|
|
// При пустом или отсутствующем query возвращаем всех пользователей
|
|
var searchQuery = string.IsNullOrWhiteSpace(query) ? "" : query;
|
|
try
|
|
{
|
|
var result = await sender.Send(new SearchUsersQuery(searchQuery), ct);
|
|
if (!result.IsSuccess)
|
|
{
|
|
Console.WriteLine($"[Admin] SearchUsers error: {result.Error.Code} - {result.Error.Description}");
|
|
return Results.BadRequest(new { error = result.Error.Description });
|
|
}
|
|
return Results.Ok(result.Value);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[Admin] SearchUsers exception: {ex}");
|
|
return Results.BadRequest(new { error = ex.Message });
|
|
}
|
|
});
|
|
|
|
group.MapGet("users/{id:guid}", async ([FromRoute] Guid id, ISender sender, CancellationToken ct) =>
|
|
{
|
|
var result = await sender.Send(new GetUserDetailsQuery(id), ct);
|
|
return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound("User not found");
|
|
});
|
|
|
|
group.MapGet("clean/dry-run", async (ISender sender, CancellationToken ct) =>
|
|
{
|
|
var result = await sender.Send(new CleanDryRunQuery(), ct);
|
|
if (!result.IsSuccess)
|
|
{
|
|
Console.WriteLine($"[Admin] Cleanup Dry Run Error: {result.Error.Description}");
|
|
return Results.BadRequest(new { error = result.Error.Description });
|
|
}
|
|
return Results.Ok(result.Value);
|
|
});
|
|
|
|
group.MapGet("timezones", () =>
|
|
{
|
|
// Получаем все системные часовые пояса и формируем удобный для фронтенда формат
|
|
var zones = TimeZoneInfo.GetSystemTimeZones()
|
|
.Select(tz => new
|
|
{
|
|
id = tz.Id,
|
|
displayName = tz.DisplayName,
|
|
standardName = tz.StandardName,
|
|
offsetMinutes = tz.BaseUtcOffset.TotalMinutes,
|
|
offsetString = (tz.BaseUtcOffset >= TimeSpan.Zero ? "+" : "-") + tz.BaseUtcOffset.ToString(@"hh\:mm")
|
|
})
|
|
.OrderBy(tz => tz.offsetMinutes);
|
|
|
|
return Results.Ok(zones);
|
|
});
|
|
}
|
|
}
|