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;
|
namespace BackOffice.BFF.WebApi.Common.Mappings;
|
||||||
|
|
||||||
using BackOffice.BFF.Application.ProductsCQ.Queries.GetCategories;
|
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;
|
using BackOffice.BFF.Products.Protobuf.Protos.Products;
|
||||||
|
|
||||||
public class ProductsProfile : IRegister
|
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.Commands.RemoveProductImage;
|
||||||
using BackOffice.BFF.Application.ProductsCQ.Queries.GetCategories;
|
using BackOffice.BFF.Application.ProductsCQ.Queries.GetCategories;
|
||||||
using BackOffice.BFF.Application.ProductsCQ.Commands.UpdateProductCategories;
|
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;
|
namespace BackOffice.BFF.WebApi.Services;
|
||||||
|
|
||||||
@@ -71,4 +73,14 @@ public class ProductsService : ProductsContract.ProductsContractBase
|
|||||||
{
|
{
|
||||||
return await _dispatchRequestToCQRS.Handle<UpdateProductCategoriesRequest, UpdateProductCategoriesCommand>(request, context);
|
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>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<Version>0.0.3</Version>
|
<Version>0.0.4</Version>
|
||||||
<DebugType>None</DebugType>
|
<DebugType>None</DebugType>
|
||||||
<DebugSymbols>False</DebugSymbols>
|
<DebugSymbols>False</DebugSymbols>
|
||||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||||
|
|||||||
@@ -73,6 +73,19 @@ service ProductsContract
|
|||||||
body: "*"
|
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
|
message ImageFileModel
|
||||||
@@ -269,3 +282,26 @@ message UpdateProductCategoriesRequest
|
|||||||
int64 product_id = 1;
|
int64 product_id = 1;
|
||||||
repeated int64 category_ids = 2;
|
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