Исправления сваггер
This commit is contained in:
@@ -6,24 +6,101 @@ namespace Nashel.Modules.Catalog.Application.Common;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// DTO категории.
|
/// DTO категории.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public record CategoryDto(
|
public record CategoryDto
|
||||||
Guid Id,
|
{
|
||||||
string Title,
|
/// <summary>
|
||||||
string Slug,
|
/// Уникальный идентификатор категории.
|
||||||
Guid? ParentId,
|
/// </summary>
|
||||||
JsonDocument? AttributeSchema
|
public Guid Id { get; init; }
|
||||||
);
|
|
||||||
|
/// <summary>
|
||||||
|
/// Название категории.
|
||||||
|
/// </summary>
|
||||||
|
public string Title { get; init; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// URL-совместимый идентификатор (slug).
|
||||||
|
/// </summary>
|
||||||
|
public string Slug { get; init; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Идентификатор родительской категории (null, если корневая).
|
||||||
|
/// </summary>
|
||||||
|
public Guid? ParentId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// JSON-схема характеристик, специфичных для категории.
|
||||||
|
/// </summary>
|
||||||
|
public JsonDocument? AttributeSchema { get; init; }
|
||||||
|
|
||||||
|
public CategoryDto(Guid id, string title, string slug, Guid? parentId, JsonDocument? attributeSchema)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Title = title;
|
||||||
|
Slug = slug;
|
||||||
|
ParentId = parentId;
|
||||||
|
AttributeSchema = attributeSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CategoryDto() { }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DTO услуги/оффера.
|
/// DTO услуги/оффера.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public record OfferDto(
|
public record OfferDto
|
||||||
Guid Id,
|
{
|
||||||
Guid OwnerId,
|
/// <summary>
|
||||||
Guid CategoryId,
|
/// Уникальный идентификатор услуги.
|
||||||
string Title,
|
/// </summary>
|
||||||
string Description,
|
public Guid Id { get; init; }
|
||||||
Price Price,
|
|
||||||
JsonDocument? Attributes,
|
/// <summary>
|
||||||
bool IsActive
|
/// Идентификатор владельца (исполнителя).
|
||||||
);
|
/// </summary>
|
||||||
|
public Guid OwnerId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Идентификатор категории.
|
||||||
|
/// </summary>
|
||||||
|
public Guid CategoryId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Заголовок услуги.
|
||||||
|
/// </summary>
|
||||||
|
public string Title { get; init; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Подробное описание услуги.
|
||||||
|
/// </summary>
|
||||||
|
public string Description { get; init; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Цена услуги.
|
||||||
|
/// </summary>
|
||||||
|
public Price Price { get; init; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// JSON-объект с характеристиками услуги.
|
||||||
|
/// </summary>
|
||||||
|
public JsonDocument? Attributes { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Флаг активности услуги.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsActive { get; init; }
|
||||||
|
|
||||||
|
public OfferDto(Guid id, Guid ownerId, Guid categoryId, string title, string description, Price price, JsonDocument? attributes, bool isActive)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
OwnerId = ownerId;
|
||||||
|
CategoryId = categoryId;
|
||||||
|
Title = title;
|
||||||
|
Description = description;
|
||||||
|
Price = price;
|
||||||
|
Attributes = attributes;
|
||||||
|
IsActive = isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferDto() { }
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public static class CatalogEndpoints
|
|||||||
return Results.Ok(id);
|
return Results.Ok(id);
|
||||||
})
|
})
|
||||||
.WithName("CreateCategory")
|
.WithName("CreateCategory")
|
||||||
.WithSummary("Создать категорию (Admin)");
|
.WithOpenApi(operation => new(operation) { Summary = "Создать категорию (Admin)", Description = "Создает новую категорию. Требуются права администратора." });
|
||||||
|
|
||||||
catalogGroup.MapGet("/categories", async (ISender sender) =>
|
catalogGroup.MapGet("/categories", async (ISender sender) =>
|
||||||
{
|
{
|
||||||
@@ -33,7 +33,7 @@ public static class CatalogEndpoints
|
|||||||
return Results.Ok(result);
|
return Results.Ok(result);
|
||||||
})
|
})
|
||||||
.WithName("GetCategories")
|
.WithName("GetCategories")
|
||||||
.WithSummary("Получить все категории (плоский список с ParentId)");
|
.WithOpenApi(operation => new(operation) { Summary = "Получить все категории", Description = "Возвращает плоский список категорий с указанием ParentId для иерархии." });
|
||||||
|
|
||||||
// --- Услуги (Offers) ---
|
// --- Услуги (Offers) ---
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ public static class CatalogEndpoints
|
|||||||
return Results.Ok(id);
|
return Results.Ok(id);
|
||||||
})
|
})
|
||||||
.WithName("CreateOffer")
|
.WithName("CreateOffer")
|
||||||
.WithSummary("Создать оффер/услугу");
|
.WithOpenApi(operation => new(operation) { Summary = "Создать оффер/услугу", Description = "Создает новое предложение услуги в указанной категории." });
|
||||||
|
|
||||||
catalogGroup.MapGet("/offers/{id:guid}", async (Guid id, ISender sender) =>
|
catalogGroup.MapGet("/offers/{id:guid}", async (Guid id, ISender sender) =>
|
||||||
{
|
{
|
||||||
@@ -51,6 +51,6 @@ public static class CatalogEndpoints
|
|||||||
return result is not null ? Results.Ok(result) : Results.NotFound();
|
return result is not null ? Results.Ok(result) : Results.NotFound();
|
||||||
})
|
})
|
||||||
.WithName("GetOfferById")
|
.WithName("GetOfferById")
|
||||||
.WithSummary("Получить детали услуги по ID");
|
.WithOpenApi(operation => new(operation) { Summary = "Получить детали услуги по ID", Description = "Возвращает полную информацию об услуге." });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,4 +13,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.4" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -24,7 +24,9 @@ public static class GeoEndpoints
|
|||||||
var command = new UpdateGeoCommand(request.PerformerId, request.Latitude, request.Longitude, request.Status);
|
var command = new UpdateGeoCommand(request.PerformerId, request.Latitude, request.Longitude, request.Status);
|
||||||
await sender.Send(command, ct);
|
await sender.Send(command, ct);
|
||||||
return Results.Ok();
|
return Results.Ok();
|
||||||
});
|
})
|
||||||
|
.WithName("UpdateGeoStatus")
|
||||||
|
.WithOpenApi(operation => new(operation) { Summary = "Обновить геопозицию и статус", Description = "Обновляет координаты и статус исполнителя (Available, Busy, DayOff)." });
|
||||||
|
|
||||||
// GET /api/geo/nearby
|
// GET /api/geo/nearby
|
||||||
group.MapGet("nearby", async (
|
group.MapGet("nearby", async (
|
||||||
@@ -36,7 +38,9 @@ public static class GeoEndpoints
|
|||||||
{
|
{
|
||||||
var result = await sender.Send(new SearchNearbyQuery(lat, lon, radius), ct);
|
var result = await sender.Send(new SearchNearbyQuery(lat, lon, radius), ct);
|
||||||
return Results.Ok(result);
|
return Results.Ok(result);
|
||||||
});
|
})
|
||||||
|
.WithName("SearchNearby")
|
||||||
|
.WithOpenApi(operation => new(operation) { Summary = "Поиск исполнителей рядом", Description = "Возвращает список ID исполнителей в радиусе поиска." });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -14,4 +14,8 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.4" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -16,13 +16,17 @@ public static class IdentityEndpoints
|
|||||||
{
|
{
|
||||||
var result = await sender.Send(command);
|
var result = await sender.Send(command);
|
||||||
return Results.Ok(result);
|
return Results.Ok(result);
|
||||||
});
|
})
|
||||||
|
.WithName("Register")
|
||||||
|
.WithOpenApi(operation => new(operation) { Summary = "Регистрация пользователя", Description = "Регистрирует нового пользователя по номеру телефона и паролю." });
|
||||||
|
|
||||||
authGroup.MapPost("/login", async (LoginCommand command, ISender sender) =>
|
authGroup.MapPost("/login", async (LoginCommand command, ISender sender) =>
|
||||||
{
|
{
|
||||||
var token = await sender.Send(command);
|
var token = await sender.Send(command);
|
||||||
return Results.Ok(new { Token = token });
|
return Results.Ok(new LoginResponse(token));
|
||||||
});
|
})
|
||||||
|
.WithName("Login")
|
||||||
|
.WithOpenApi(operation => new(operation) { Summary = "Вход в систему", Description = "Аутентификация пользователя и получение JWT токена." });
|
||||||
|
|
||||||
var profileGroup = app.MapGroup("/api/profile").WithTags("Profile").RequireAuthorization();
|
var profileGroup = app.MapGroup("/api/profile").WithTags("Profile").RequireAuthorization();
|
||||||
|
|
||||||
@@ -30,6 +34,14 @@ public static class IdentityEndpoints
|
|||||||
{
|
{
|
||||||
await sender.Send(new BecomePerformerCommand());
|
await sender.Send(new BecomePerformerCommand());
|
||||||
return Results.Ok();
|
return Results.Ok();
|
||||||
});
|
})
|
||||||
|
.WithName("BecomePerformer")
|
||||||
|
.WithOpenApi(operation => new(operation) { Summary = "Стать исполнителем", Description = "Присваивает текущему пользователю роль исполнителя." });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ответ на успешный вход в систему.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Token">JWT токен доступа.</param>
|
||||||
|
public record LoginResponse(string Token);
|
||||||
|
|||||||
@@ -13,4 +13,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.4" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MediatR" Version="14.0.0" />
|
<PackageReference Include="MediatR" Version="14.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public static class OrderEndpoints
|
|||||||
return Results.Ok();
|
return Results.Ok();
|
||||||
})
|
})
|
||||||
.WithName("AddOrderApplication")
|
.WithName("AddOrderApplication")
|
||||||
.WithOpenApi(operation => new(operation) { Summary = "Добавление отклика на заказ." });
|
.WithOpenApi(operation => new(operation) { Summary = "Добавление отклика на заказ.", Description = "Позволяет исполнителю откликнуться на заказ." });
|
||||||
|
|
||||||
group.MapPost("/{id:guid}/select-performer", async (Guid id, SelectPerformerRequest request, ISender sender) =>
|
group.MapPost("/{id:guid}/select-performer", async (Guid id, SelectPerformerRequest request, ISender sender) =>
|
||||||
{
|
{
|
||||||
@@ -53,35 +53,95 @@ public static class OrderEndpoints
|
|||||||
return Results.Ok();
|
return Results.Ok();
|
||||||
})
|
})
|
||||||
.WithName("SelectPerformer")
|
.WithName("SelectPerformer")
|
||||||
.WithOpenApi(operation => new(operation) { Summary = "Выбор исполнителя для заказа." });
|
.WithOpenApi(operation => new(operation) { Summary = "Выбор исполнителя для заказа.", Description = "Позволяет заказчику выбрать конкретного исполнителя." });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Запрос на создание заказа.
|
/// Запрос на создание заказа.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public record CreateOrderRequest(
|
public record CreateOrderRequest
|
||||||
Guid CustomerId,
|
{
|
||||||
Guid ServiceId,
|
/// <summary>
|
||||||
OrderType Type,
|
/// Идентификатор заказчика.
|
||||||
string Address,
|
/// </summary>
|
||||||
double Latitude,
|
public Guid CustomerId { get; init; }
|
||||||
double Longitude,
|
|
||||||
DateTime? Deadline,
|
/// <summary>
|
||||||
Guid? PerformerId
|
/// Идентификатор услуги.
|
||||||
);
|
/// </summary>
|
||||||
|
public Guid ServiceId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Тип заказа (прямой, публичный).
|
||||||
|
/// </summary>
|
||||||
|
public OrderType Type { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Текстовый адрес выполнения заказа.
|
||||||
|
/// </summary>
|
||||||
|
public string Address { get; init; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Географическая широта места выполнения.
|
||||||
|
/// </summary>
|
||||||
|
public double Latitude { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Географическая долгота места выполнения.
|
||||||
|
/// </summary>
|
||||||
|
public double Longitude { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Крайний срок выполнения заказа (опционально).
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? Deadline { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Идентификатор конкретного исполнителя (если прямой заказ).
|
||||||
|
/// </summary>
|
||||||
|
public Guid? PerformerId { get; init; }
|
||||||
|
|
||||||
|
public CreateOrderRequest() { }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Запрос на добавление отклика.
|
/// Запрос на добавление отклика.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public record AddApplicationRequest(
|
public record AddApplicationRequest
|
||||||
Guid PerformerId,
|
{
|
||||||
decimal Amount,
|
/// <summary>
|
||||||
string Currency,
|
/// Идентификатор исполнителя.
|
||||||
string Comment
|
/// </summary>
|
||||||
);
|
public Guid PerformerId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сумма предложения.
|
||||||
|
/// </summary>
|
||||||
|
public decimal Amount { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Валюта предложения (например, RUB).
|
||||||
|
/// </summary>
|
||||||
|
public string Currency { get; init; } = "RUB";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Комментарий к отклику.
|
||||||
|
/// </summary>
|
||||||
|
public string Comment { get; init; } = default!;
|
||||||
|
|
||||||
|
public AddApplicationRequest() { }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Запрос на выбор исполнителя.
|
/// Запрос на выбор исполнителя.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public record SelectPerformerRequest(Guid PerformerId);
|
public record SelectPerformerRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Идентификатор выбранного исполнителя.
|
||||||
|
/// </summary>
|
||||||
|
public Guid PerformerId { get; init; }
|
||||||
|
|
||||||
|
public SelectPerformerRequest() { }
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user