Add category products query and update endpoints
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Commands.UpdateCategoryProducts;
|
||||
|
||||
public record UpdateCategoryProductsCommand : IRequest<Unit>
|
||||
{
|
||||
public long CategoryId { get; init; }
|
||||
public IReadOnlyCollection<long> ProductIds { get; init; } = Array.Empty<long>();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
using BackOffice.BFF.Application.Common.Interfaces;
|
||||
using CMSPruductCategory = CMSMicroservice.Protobuf.Protos.PruductCategory;
|
||||
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Commands.UpdateCategoryProducts;
|
||||
|
||||
public class UpdateCategoryProductsCommandHandler : IRequestHandler<UpdateCategoryProductsCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public UpdateCategoryProductsCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(UpdateCategoryProductsCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var targetIds = request.ProductIds?.ToHashSet() ?? new HashSet<long>();
|
||||
|
||||
// load existing links for this category
|
||||
var existingRequest = new CMSPruductCategory.GetAllPruductCategoryByFilterRequest
|
||||
{
|
||||
Filter = new CMSPruductCategory.GetAllPruductCategoryByFilterFilter
|
||||
{
|
||||
CategoryId = request.CategoryId
|
||||
},
|
||||
PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState
|
||||
{
|
||||
PageNumber = 1,
|
||||
PageSize = 1000
|
||||
}
|
||||
};
|
||||
|
||||
var existingResponse = await _context.ProductCategories.GetAllPruductCategoryByFilterAsync(existingRequest, cancellationToken: cancellationToken);
|
||||
var existing = existingResponse.Models ?? new();
|
||||
|
||||
var existingIds = existing.Select(x => x.ProductId).ToHashSet();
|
||||
|
||||
var toAdd = targetIds.Except(existingIds).ToList();
|
||||
var toRemove = existing.Where(x => !targetIds.Contains(x.ProductId)).ToList();
|
||||
|
||||
foreach (var productId in toAdd)
|
||||
{
|
||||
var createRequest = new CMSPruductCategory.CreateNewPruductCategoryRequest
|
||||
{
|
||||
ProductId = productId,
|
||||
CategoryId = request.CategoryId
|
||||
};
|
||||
|
||||
await _context.ProductCategories.CreateNewPruductCategoryAsync(createRequest, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
foreach (var rel in toRemove)
|
||||
{
|
||||
await _context.ProductCategories.DeletePruductCategoryAsync(
|
||||
new CMSPruductCategory.DeletePruductCategoryRequest { Id = rel.Id },
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetProductsForCategory;
|
||||
|
||||
public record GetProductsForCategoryQuery : IRequest<GetProductsForCategoryResponseDto>
|
||||
{
|
||||
public long CategoryId { get; init; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
using BackOffice.BFF.Application.Common.Interfaces;
|
||||
using CMSProducts = CMSMicroservice.Protobuf.Protos.Products;
|
||||
using CMSPruductCategory = CMSMicroservice.Protobuf.Protos.PruductCategory;
|
||||
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetProductsForCategory;
|
||||
|
||||
public class GetProductsForCategoryQueryHandler : IRequestHandler<GetProductsForCategoryQuery, GetProductsForCategoryResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetProductsForCategoryQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetProductsForCategoryResponseDto> Handle(GetProductsForCategoryQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
// Load all products
|
||||
var productsRequest = new CMSProducts.GetAllProductsByFilterRequest
|
||||
{
|
||||
Filter = new CMSProducts.GetAllProductsByFilterFilter(),
|
||||
PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState
|
||||
{
|
||||
PageNumber = 1,
|
||||
PageSize = 1000
|
||||
}
|
||||
};
|
||||
|
||||
var productsResponse = await _context.Products.GetAllProductsByFilterAsync(productsRequest, cancellationToken: cancellationToken);
|
||||
var products = productsResponse.Models ?? new();
|
||||
|
||||
// Load links for this category
|
||||
var linksRequest = new CMSPruductCategory.GetAllPruductCategoryByFilterRequest
|
||||
{
|
||||
Filter = new CMSPruductCategory.GetAllPruductCategoryByFilterFilter
|
||||
{
|
||||
CategoryId = request.CategoryId
|
||||
},
|
||||
PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState
|
||||
{
|
||||
PageNumber = 1,
|
||||
PageSize = 1000
|
||||
}
|
||||
};
|
||||
|
||||
var linksResponse = await _context.ProductCategories.GetAllPruductCategoryByFilterAsync(linksRequest, cancellationToken: cancellationToken);
|
||||
var links = linksResponse.Models ?? new();
|
||||
|
||||
var selectedProductIds = links.Select(l => l.ProductId).ToHashSet();
|
||||
|
||||
var result = new GetProductsForCategoryResponseDto
|
||||
{
|
||||
Items = products
|
||||
.Select(p => new CategoryProductItemDto
|
||||
{
|
||||
Id = p.Id,
|
||||
Title = p.Title,
|
||||
Selected = selectedProductIds.Contains(p.Id)
|
||||
})
|
||||
.ToList()
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetProductsForCategory;
|
||||
|
||||
public class GetProductsForCategoryResponseDto
|
||||
{
|
||||
public List<CategoryProductItemDto> Items { get; set; } = new();
|
||||
}
|
||||
|
||||
public class CategoryProductItemDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Title { get; set; } = string.Empty;
|
||||
public bool Selected { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace BackOffice.BFF.WebApi.Common.Mappings;
|
||||
|
||||
using BackOffice.BFF.Application.ProductsCQ.Queries.GetCategories;
|
||||
using BackOffice.BFF.Application.ProductsCQ.Queries.GetProductsForCategory;
|
||||
using BackOffice.BFF.Application.ProductsCQ.Queries.GetProductGallery;
|
||||
using BackOffice.BFF.Products.Protobuf.Protos.Products;
|
||||
|
||||
public class ProductsProfile : IRegister
|
||||
@@ -22,6 +24,39 @@ public class ProductsProfile : IRegister
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// Map GetProductsForCategory response DTO to protobuf response
|
||||
config.NewConfig<GetProductsForCategoryResponseDto, GetProductsForCategoryResponse>()
|
||||
.MapWith(src => new GetProductsForCategoryResponse
|
||||
{
|
||||
Items =
|
||||
{
|
||||
(src.Items ?? Enumerable.Empty<CategoryProductItemDto>())
|
||||
.Select(x => new CategoryProductItem
|
||||
{
|
||||
Id = x.Id,
|
||||
Title = x.Title ?? string.Empty,
|
||||
Selected = x.Selected
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// Map GetProductGallery response DTO to protobuf response
|
||||
config.NewConfig<GetProductGalleryResponseDto, GetProductGalleryResponse>()
|
||||
.MapWith(src => new GetProductGalleryResponse
|
||||
{
|
||||
Items =
|
||||
{
|
||||
(src.Items ?? Enumerable.Empty<ProductGalleryItemDto>())
|
||||
.Select(x => new ProductGalleryItem
|
||||
{
|
||||
ProductGalleryId = x.ProductGalleryId,
|
||||
ProductImageId = x.ProductImageId,
|
||||
Title = x.Title ?? string.Empty,
|
||||
ImagePath = x.ImagePath ?? string.Empty,
|
||||
ImageThumbnailPath = x.ImageThumbnailPath ?? string.Empty
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ using BackOffice.BFF.Application.ProductsCQ.Queries.GetProductGallery;
|
||||
using BackOffice.BFF.Application.ProductsCQ.Commands.RemoveProductImage;
|
||||
using BackOffice.BFF.Application.ProductsCQ.Queries.GetCategories;
|
||||
using BackOffice.BFF.Application.ProductsCQ.Commands.UpdateProductCategories;
|
||||
using BackOffice.BFF.Application.ProductsCQ.Queries.GetProductsForCategory;
|
||||
using BackOffice.BFF.Application.ProductsCQ.Commands.UpdateCategoryProducts;
|
||||
|
||||
namespace BackOffice.BFF.WebApi.Services;
|
||||
|
||||
@@ -71,4 +73,14 @@ public class ProductsService : ProductsContract.ProductsContractBase
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<UpdateProductCategoriesRequest, UpdateProductCategoriesCommand>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<GetProductsForCategoryResponse> GetProductsForCategory(GetProductsForCategoryRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetProductsForCategoryRequest, GetProductsForCategoryQuery, GetProductsForCategoryResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<Empty> UpdateCategoryProducts(UpdateCategoryProductsRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<UpdateCategoryProductsRequest, UpdateCategoryProductsCommand>(request, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>0.0.3</Version>
|
||||
<Version>0.0.4</Version>
|
||||
<DebugType>None</DebugType>
|
||||
<DebugSymbols>False</DebugSymbols>
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
|
||||
@@ -73,6 +73,19 @@ service ProductsContract
|
||||
body: "*"
|
||||
};
|
||||
};
|
||||
|
||||
rpc GetProductsForCategory(GetProductsForCategoryRequest) returns (GetProductsForCategoryResponse){
|
||||
option (google.api.http) = {
|
||||
get: "/GetProductsForCategory"
|
||||
};
|
||||
};
|
||||
|
||||
rpc UpdateCategoryProducts(UpdateCategoryProductsRequest) returns (google.protobuf.Empty){
|
||||
option (google.api.http) = {
|
||||
post: "/UpdateCategoryProducts"
|
||||
body: "*"
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
message ImageFileModel
|
||||
@@ -269,3 +282,26 @@ message UpdateProductCategoriesRequest
|
||||
int64 product_id = 1;
|
||||
repeated int64 category_ids = 2;
|
||||
}
|
||||
|
||||
message CategoryProductItem
|
||||
{
|
||||
int64 id = 1;
|
||||
string title = 2;
|
||||
bool selected = 3;
|
||||
}
|
||||
|
||||
message GetProductsForCategoryRequest
|
||||
{
|
||||
int64 category_id = 1;
|
||||
}
|
||||
|
||||
message GetProductsForCategoryResponse
|
||||
{
|
||||
repeated CategoryProductItem items = 1;
|
||||
}
|
||||
|
||||
message UpdateCategoryProductsRequest
|
||||
{
|
||||
int64 category_id = 1;
|
||||
repeated int64 product_ids = 2;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user