update 2
This commit is contained in:
@@ -5,6 +5,8 @@ using CMSMicroservice.Protobuf.Protos.UserAddress;
|
||||
using CMSMicroservice.Protobuf.Protos.UserOrder;
|
||||
using CMSMicroservice.Protobuf.Protos.UserRole;
|
||||
using CMSMicroservice.Protobuf.Protos.Products;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductImages;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
|
||||
using FMSMicroservice.Protobuf.Protos.FileInfo;
|
||||
|
||||
namespace BackOffice.BFF.Application.Common.Interfaces;
|
||||
@@ -17,6 +19,8 @@ public interface IApplicationContractContext
|
||||
#region CMS
|
||||
PackageContract.PackageContractClient Packages { get; }
|
||||
ProductsContract.ProductsContractClient Products { get; }
|
||||
ProductImagesContract.ProductImagesContractClient ProductImages { get; }
|
||||
ProductGallerysContract.ProductGallerysContractClient ProductGallerys { get; }
|
||||
RoleContract.RoleContractClient Roles { get; }
|
||||
UserAddressContract.UserAddressContractClient UserAddress { get; }
|
||||
UserContract.UserContractClient Users { get; }
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Commands.AddProductImage;
|
||||
|
||||
public record AddProductImageCommand : IRequest<AddProductImageResponseDto>
|
||||
{
|
||||
public long ProductId { get; init; }
|
||||
public string Title { get; init; }
|
||||
public ImageFileModel ImageFile { get; init; }
|
||||
}
|
||||
|
||||
public class ImageFileModel
|
||||
{
|
||||
public byte[] File { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public string Mime { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
using System.IO;
|
||||
using BackOffice.BFF.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductImages;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
|
||||
using Google.Protobuf;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Commands.AddProductImage;
|
||||
|
||||
public class AddProductImageCommandHandler : IRequestHandler<AddProductImageCommand, AddProductImageResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public AddProductImageCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<AddProductImageResponseDto> Handle(AddProductImageCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
if (request.ImageFile == null || request.ImageFile.File == null || request.ImageFile.File.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("Image file is required.");
|
||||
}
|
||||
|
||||
var optimizedMainImage = OptimizeImage(request.ImageFile.File, 1200, 1200, 80);
|
||||
var thumbnailImage = OptimizeImage(request.ImageFile.File, 300, 300, 75);
|
||||
|
||||
var mainFileInfo = await _context.FileInfos.CreateNewFileInfoAsync(new()
|
||||
{
|
||||
Directory = "Images/Products/Gallery",
|
||||
IsBase64 = false,
|
||||
MIME = request.ImageFile.Mime,
|
||||
FileName = request.ImageFile.FileName,
|
||||
File = ByteString.CopyFrom(optimizedMainImage)
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
var thumbFileInfo = await _context.FileInfos.CreateNewFileInfoAsync(new()
|
||||
{
|
||||
Directory = "Images/Products/Gallery/Thumbnail",
|
||||
IsBase64 = false,
|
||||
MIME = request.ImageFile.Mime,
|
||||
FileName = request.ImageFile.FileName,
|
||||
File = ByteString.CopyFrom(thumbnailImage)
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
if (mainFileInfo == null || string.IsNullOrWhiteSpace(mainFileInfo.File) ||
|
||||
thumbFileInfo == null || string.IsNullOrWhiteSpace(thumbFileInfo.File))
|
||||
{
|
||||
throw new InvalidOperationException("Error while uploading gallery image.");
|
||||
}
|
||||
|
||||
var createImageResponse = await _context.ProductImages.CreateNewProductImagesAsync(new CreateNewProductImagesRequest
|
||||
{
|
||||
Title = request.Title ?? string.Empty,
|
||||
ImagePath = mainFileInfo.File,
|
||||
ImageThumbnailPath = thumbFileInfo.File
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
var createGalleryResponse = await _context.ProductGallerys.CreateNewProductGallerysAsync(new CreateNewProductGallerysRequest
|
||||
{
|
||||
ProductId = request.ProductId,
|
||||
ProductImageId = createImageResponse.Id
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
return new AddProductImageResponseDto
|
||||
{
|
||||
ProductGalleryId = createGalleryResponse.Id,
|
||||
ProductImageId = createImageResponse.Id,
|
||||
Title = request.Title ?? string.Empty,
|
||||
ImagePath = mainFileInfo.File,
|
||||
ImageThumbnailPath = thumbFileInfo.File
|
||||
};
|
||||
}
|
||||
|
||||
private static byte[] OptimizeImage(byte[] original, int maxWidth, int maxHeight, int quality)
|
||||
{
|
||||
using var image = Image.Load(original);
|
||||
|
||||
var ratio = Math.Min(maxWidth / (float)image.Width, maxHeight / (float)image.Height);
|
||||
if (ratio < 1f)
|
||||
{
|
||||
var width = (int)(image.Width * ratio);
|
||||
var height = (int)(image.Height * ratio);
|
||||
image.Mutate(x => x.Resize(width, height));
|
||||
}
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
image.Save(ms, new JpegEncoder { Quality = quality });
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Commands.AddProductImage;
|
||||
|
||||
public class AddProductImageResponseDto
|
||||
{
|
||||
public long ProductGalleryId { get; set; }
|
||||
public long ProductImageId { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string ImagePath { get; set; }
|
||||
public string ImageThumbnailPath { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Commands.RemoveProductImage;
|
||||
|
||||
public record RemoveProductImageCommand : IRequest<Unit>
|
||||
{
|
||||
public long ProductGalleryId { get; init; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using BackOffice.BFF.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
|
||||
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Commands.RemoveProductImage;
|
||||
|
||||
public class RemoveProductImageCommandHandler : IRequestHandler<RemoveProductImageCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public RemoveProductImageCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(RemoveProductImageCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _context.ProductGallerys.DeleteProductGallerysAsync(new DeleteProductGallerysRequest
|
||||
{
|
||||
Id = request.ProductGalleryId
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetProductGallery;
|
||||
|
||||
public record GetProductGalleryQuery : IRequest<GetProductGalleryResponseDto>
|
||||
{
|
||||
public long ProductId { get; init; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
using BackOffice.BFF.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductImages;
|
||||
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetProductGallery;
|
||||
|
||||
public class GetProductGalleryQueryHandler : IRequestHandler<GetProductGalleryQuery, GetProductGalleryResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetProductGalleryQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetProductGalleryResponseDto> Handle(GetProductGalleryQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var galleryRequest = new GetAllProductGallerysByFilterRequest
|
||||
{
|
||||
Filter = new GetAllProductGallerysByFilterFilter()
|
||||
};
|
||||
|
||||
var galleryResponse = await _context.ProductGallerys.GetAllProductGallerysByFilterAsync(galleryRequest, cancellationToken: cancellationToken);
|
||||
|
||||
// Filter by product id on client side because generated type may not support assigning Int64Value directly
|
||||
var filteredModels = galleryResponse?.Models?.Where(x => x.ProductId == request.ProductId).ToList();
|
||||
|
||||
var result = new GetProductGalleryResponseDto();
|
||||
|
||||
if (filteredModels == null || filteredModels.Count == 0)
|
||||
return result;
|
||||
|
||||
foreach (var item in filteredModels)
|
||||
{
|
||||
var image = await _context.ProductImages.GetProductImagesAsync(new GetProductImagesRequest
|
||||
{
|
||||
Id = item.ProductImageId
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
if (image == null)
|
||||
continue;
|
||||
|
||||
result.Items.Add(new ProductGalleryItemDto
|
||||
{
|
||||
ProductGalleryId = item.Id,
|
||||
ProductImageId = item.ProductImageId,
|
||||
Title = image.Title,
|
||||
ImagePath = image.ImagePath,
|
||||
ImageThumbnailPath = image.ImageThumbnailPath
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetProductGallery;
|
||||
|
||||
public class GetProductGalleryResponseDto
|
||||
{
|
||||
public List<ProductGalleryItemDto> Items { get; set; } = new();
|
||||
}
|
||||
|
||||
public class ProductGalleryItemDto
|
||||
{
|
||||
public long ProductGalleryId { get; set; }
|
||||
public long ProductImageId { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string ImagePath { get; set; }
|
||||
public string ImageThumbnailPath { get; set; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user