Add product categories CQRS handlers and gRPC endpoints

This commit is contained in:
masoodafar-web
2025-11-27 03:46:51 +03:30
parent ad3cc728df
commit 8340a932ce
7 changed files with 118 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
namespace BackOffice.BFF.Application.ProductsCQ.Commands.UpdateProductCategories;
public record UpdateProductCategoriesCommand : IRequest<Unit>
{
public long ProductId { get; init; }
public IReadOnlyCollection<long> CategoryIds { get; init; } = Array.Empty<long>();
}

View File

@@ -0,0 +1,21 @@
using BackOffice.BFF.Application.Common.Interfaces;
namespace BackOffice.BFF.Application.ProductsCQ.Commands.UpdateProductCategories;
public class UpdateProductCategoriesCommandHandler : IRequestHandler<UpdateProductCategoriesCommand, Unit>
{
private readonly IApplicationContractContext _context;
public UpdateProductCategoriesCommandHandler(IApplicationContractContext context)
{
_context = context;
}
public async Task<Unit> Handle(UpdateProductCategoriesCommand request, CancellationToken cancellationToken)
{
// Stub: until CMS Category services are available via the protobuf package,
// this handler is a no-op to keep the pipeline consistent.
await Task.CompletedTask;
return Unit.Value;
}
}

View File

@@ -0,0 +1,7 @@
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetCategories;
public record GetCategoriesQuery : IRequest<GetCategoriesResponseDto>
{
public long ProductId { get; init; }
}

View File

@@ -0,0 +1,20 @@
using BackOffice.BFF.Application.Common.Interfaces;
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetCategories;
public class GetCategoriesQueryHandler : IRequestHandler<GetCategoriesQuery, GetCategoriesResponseDto>
{
public GetCategoriesQueryHandler(IApplicationContractContext context)
{
// context is currently unused; reserved for future CMS integration
}
public async Task<GetCategoriesResponseDto> Handle(GetCategoriesQuery request, CancellationToken cancellationToken)
{
// Stub implementation: returns empty list.
// When CMS protobuf package with Category support is available,
// this handler can be updated to call Category and PruductCategory services.
await Task.CompletedTask;
return new GetCategoriesResponseDto();
}
}

View File

@@ -0,0 +1,14 @@
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetCategories;
public class GetCategoriesResponseDto
{
public List<CategoryItemDto> Items { get; set; } = new();
}
public class CategoryItemDto
{
public long Id { get; set; }
public string Title { get; set; }
public bool Selected { get; set; }
}

View File

@@ -8,6 +8,8 @@ using BackOffice.BFF.Application.ProductsCQ.Queries.GetAllProductsByFilter;
using BackOffice.BFF.Application.ProductsCQ.Commands.AddProductImage; using BackOffice.BFF.Application.ProductsCQ.Commands.AddProductImage;
using BackOffice.BFF.Application.ProductsCQ.Queries.GetProductGallery; using BackOffice.BFF.Application.ProductsCQ.Queries.GetProductGallery;
using BackOffice.BFF.Application.ProductsCQ.Commands.RemoveProductImage; using BackOffice.BFF.Application.ProductsCQ.Commands.RemoveProductImage;
using BackOffice.BFF.Application.ProductsCQ.Queries.GetCategories;
using BackOffice.BFF.Application.ProductsCQ.Commands.UpdateProductCategories;
namespace BackOffice.BFF.WebApi.Services; namespace BackOffice.BFF.WebApi.Services;
@@ -59,4 +61,14 @@ public class ProductsService : ProductsContract.ProductsContractBase
{ {
return await _dispatchRequestToCQRS.Handle<RemoveProductImageRequest, RemoveProductImageCommand>(request, context); return await _dispatchRequestToCQRS.Handle<RemoveProductImageRequest, RemoveProductImageCommand>(request, context);
} }
public override async Task<GetCategoriesResponse> GetCategories(GetCategoriesRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<GetCategoriesRequest, GetCategoriesQuery, GetCategoriesResponse>(request, context);
}
public override async Task<Empty> UpdateProductCategories(UpdateProductCategoriesRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<UpdateProductCategoriesRequest, UpdateProductCategoriesCommand>(request, context);
}
} }

View File

@@ -60,6 +60,19 @@ service ProductsContract
body: "*" body: "*"
}; };
}; };
rpc GetCategories(GetCategoriesRequest) returns (GetCategoriesResponse){
option (google.api.http) = {
get: "/GetCategories"
};
};
rpc UpdateProductCategories(UpdateProductCategoriesRequest) returns (google.protobuf.Empty){
option (google.api.http) = {
post: "/UpdateProductCategories"
body: "*"
};
};
} }
message ImageFileModel message ImageFileModel
@@ -233,3 +246,26 @@ message RemoveProductImageRequest
{ {
int64 product_gallery_id = 1; int64 product_gallery_id = 1;
} }
message CategoryItem
{
int64 id = 1;
string title = 2;
bool selected = 3;
}
message GetCategoriesRequest
{
int64 product_id = 1;
}
message GetCategoriesResponse
{
repeated CategoryItem items = 1;
}
message UpdateProductCategoriesRequest
{
int64 product_id = 1;
repeated int64 category_ids = 2;
}