Реализован модуль каталога, миграции, сваггер

This commit is contained in:
Халимов Рустам
2026-02-10 15:32:40 +03:00
parent 4c9e44e992
commit 9d3999f690
40 changed files with 1665 additions and 4 deletions
@@ -0,0 +1,75 @@
using System.Text.Json;
using MediatR;
using Nashel.Modules.Catalog.Domain.Aggregates;
using Nashel.Modules.Catalog.Domain.Repositories;
namespace Nashel.Modules.Catalog.Application.Commands;
/// <summary>
/// Команда создания категории.
/// </summary>
public record CreateCategoryCommand : IRequest<Guid>
{
/// <summary>
/// Название категории.
/// </summary>
public string Title { get; init; }
/// <summary>
/// URL-friendly идентификатор (слаг).
/// </summary>
public string Slug { get; init; }
/// <summary>
/// ID родительской категории (null для корневых).
/// </summary>
public Guid? ParentId { get; init; }
/// <summary>
/// Шаблон характеристик (JSON).
/// </summary>
public JsonDocument? AttributeSchema { get; init; }
public CreateCategoryCommand(string title, string slug, Guid? parentId, JsonDocument? attributeSchema)
{
Title = title;
Slug = slug;
ParentId = parentId;
AttributeSchema = attributeSchema;
}
public CreateCategoryCommand() { } // For deserialization
}
public class CreateCategoryCommandHandler : IRequestHandler<CreateCategoryCommand, Guid>
{
private readonly ICategoryRepository _repository;
public CreateCategoryCommandHandler(ICategoryRepository repository)
{
_repository = repository;
}
public async Task<Guid> Handle(CreateCategoryCommand request, CancellationToken cancellationToken)
{
if (request.ParentId.HasValue)
{
var parentCategory = await _repository.GetByIdAsync(request.ParentId.Value, cancellationToken);
if (parentCategory == null)
{
throw new ApplicationException($"Родительская категория с ID {request.ParentId} не найдена.");
}
}
var category = new Category(
request.Title,
request.Slug,
request.ParentId,
request.AttributeSchema
);
await _repository.AddAsync(category, cancellationToken);
return category.Id;
}
}
@@ -0,0 +1,81 @@
using System.Text.Json;
using MediatR;
using Nashel.Modules.Catalog.Domain.Aggregates;
using Nashel.Modules.Catalog.Domain.Repositories;
using Nashel.Modules.Catalog.Domain.ValueObjects;
namespace Nashel.Modules.Catalog.Application.Commands;
/// <summary>
/// Команда создания услуги (оффера).
/// </summary>
public record CreateOfferCommand : IRequest<Guid>
{
/// <summary>
/// ID владельца (пользователя/исполнителя).
/// </summary>
public Guid OwnerId { get; init; }
/// <summary>
/// ID категории услуги.
/// </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; }
public CreateOfferCommand(Guid ownerId, Guid categoryId, string title, string description, Price price, JsonDocument? attributes)
{
OwnerId = ownerId;
CategoryId = categoryId;
Title = title;
Description = description;
Price = price;
Attributes = attributes;
}
public CreateOfferCommand() { }
}
public class CreateOfferCommandHandler : IRequestHandler<CreateOfferCommand, Guid>
{
private readonly IOfferRepository _repository;
public CreateOfferCommandHandler(IOfferRepository repository)
{
_repository = repository;
}
public async Task<Guid> Handle(CreateOfferCommand request, CancellationToken cancellationToken)
{
var offer = new Offer(
request.OwnerId,
request.CategoryId,
request.Title,
request.Description,
request.Price,
request.Attributes
);
await _repository.AddAsync(offer, cancellationToken);
return offer.Id;
}
}