111 lines
5.4 KiB
C#
111 lines
5.4 KiB
C#
using MediatR;
|
|
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Routing;
|
|
using Nashel.Modules.Catalog.Application.Commands;
|
|
using Nashel.Modules.Catalog.Application.Queries;
|
|
|
|
namespace Nashel.Modules.Catalog.Presentation.Endpoints;
|
|
|
|
/// <summary>
|
|
/// API Каталога (Категории и Услуги).
|
|
/// </summary>
|
|
public static class CatalogEndpoints
|
|
{
|
|
public static void MapCatalogEndpoints(this IEndpointRouteBuilder app)
|
|
{
|
|
var catalogGroup = app.MapGroup("/api/catalog").WithTags("Catalog");
|
|
|
|
// --- Категории ---
|
|
|
|
catalogGroup.MapPost("/categories", async ([FromBody] CreateCategoryCommand command, ISender sender) =>
|
|
{
|
|
var result = await sender.Send(command);
|
|
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error);
|
|
})
|
|
.WithName("CreateCategory")
|
|
.WithOpenApi(operation => new(operation) { Summary = "Создать категорию (Admin)", Description = "Создает новую категорию. Требуются права администратора." });
|
|
|
|
catalogGroup.MapGet("/categories", async (ISender sender) =>
|
|
{
|
|
var result = await sender.Send(new GetCategoriesQuery());
|
|
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error);
|
|
})
|
|
.WithName("GetCategories")
|
|
.WithOpenApi(operation => new(operation) { Summary = "Получить все категории", Description = "Возвращает плоский список категорий с указанием ParentId для иерархии." });
|
|
|
|
// --- Услуги (Offers) ---
|
|
|
|
var protectedOffersGroup = catalogGroup.MapGroup("").RequireAuthorization();
|
|
|
|
protectedOffersGroup.MapGet("/offers/my", async (ISender sender) =>
|
|
{
|
|
var result = await sender.Send(new GetMyOffersQuery());
|
|
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error);
|
|
})
|
|
.WithName("GetMyOffers")
|
|
.WithOpenApi(operation => new(operation) { Summary = "Получить мои услуги", Description = "Возвращает список услуг текущего пользователя." });
|
|
|
|
protectedOffersGroup.MapPost("/offers", async ([FromBody] CreateOfferCommand command, ISender sender) =>
|
|
{
|
|
var result = await sender.Send(command);
|
|
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error);
|
|
})
|
|
.WithName("CreateOffer")
|
|
.WithOpenApi(operation => new(operation) { Summary = "Создать оффер/услугу", Description = "Создает новое предложение услуги в указанной категории." });
|
|
|
|
catalogGroup.MapGet("/offers/{id:guid}", async (Guid id, ISender sender) =>
|
|
{
|
|
var result = await sender.Send(new GetOfferByIdQuery(id));
|
|
return result.IsSuccess && result.Value is not null ? Results.Ok(result.Value) : Results.NotFound();
|
|
})
|
|
.WithName("GetOfferById")
|
|
.WithOpenApi(operation => new(operation) { Summary = "Получить детали услуги по ID", Description = "Возвращает полную информацию об услуге." });
|
|
|
|
protectedOffersGroup.MapPut("/offers/{id:guid}", async (Guid id, [FromBody] UpdateOfferPayload payload, ISender sender) =>
|
|
{
|
|
var command = new UpdateOfferCommand(id, payload.Title, payload.Description, payload.Price.Amount, payload.Price.Type, payload.Attributes, payload.Images);
|
|
await sender.Send(command);
|
|
return Results.NoContent();
|
|
})
|
|
.WithName("UpdateOffer")
|
|
.WithOpenApi(operation => new(operation) { Summary = "Обновить услугу" });
|
|
|
|
protectedOffersGroup.MapPatch("/offers/{id:guid}/toggle", async (Guid id, ISender sender) =>
|
|
{
|
|
var isActive = await sender.Send(new ToggleOfferStatusCommand(id));
|
|
return Results.Ok(new { IsActive = isActive });
|
|
})
|
|
.WithName("ToggleOfferStatus")
|
|
.WithOpenApi(operation => new(operation) { Summary = "Приостановить/активировать услугу" });
|
|
|
|
protectedOffersGroup.MapDelete("/offers/{id:guid}", async (Guid id, ISender sender) =>
|
|
{
|
|
await sender.Send(new DeleteOfferCommand(id));
|
|
return Results.NoContent();
|
|
})
|
|
.WithName("DeleteOffer")
|
|
.WithOpenApi(operation => new(operation) { Summary = "Удалить услугу" });
|
|
|
|
protectedOffersGroup.MapPost("/offers/image", async (IFormFile file, ISender sender) =>
|
|
{
|
|
using var ms = new MemoryStream();
|
|
await file.CopyToAsync(ms);
|
|
var url = await sender.Send(new UploadOfferImageCommand(ms.ToArray(), file.FileName));
|
|
return Results.Ok(new { url });
|
|
})
|
|
.WithName("UploadOfferImage")
|
|
.WithOpenApi(operation => new(operation) { Summary = "Загрузить изображение для услуги" })
|
|
.DisableAntiforgery();
|
|
}
|
|
}
|
|
|
|
public record UpdateOfferPayload(
|
|
string Title,
|
|
string Description,
|
|
PricePayload Price,
|
|
Dictionary<string, string>? Attributes,
|
|
List<string>? Images);
|
|
public record PricePayload(decimal Amount, int Type);
|