From c41afe4b16e3c9f4ae57eb8770848faf757248a2 Mon Sep 17 00:00:00 2001 From: "Amir.H Khademi" Date: Thu, 15 Feb 2024 10:39:00 +0330 Subject: [PATCH] feat : SCRAPER IS HERE , version 0.5.9.17 , change product response add digikala scraper , change product response model and add pager --- .version | 2 +- NetinaShop.Api/Controller/FileController.cs | 21 +--- .../Controller/ScraperController.cs | 25 ++++ NetinaShop.Api/NetinaShop.Api.csproj | 4 +- NetinaShop.Core/Abstracts/IDigikalaScraper.cs | 9 ++ .../Abstracts/IUploadFileService.cs | 6 + NetinaShop.Core/NetinaShop.Core.csproj | 1 + .../CommandQueries/Queries/ProductQueries.cs | 4 +- .../ResponseDtos/GetProductResponseDto.cs | 6 + .../ResponseDtos/GetProductsResponseDto.cs | 8 ++ .../Dtos/ResponseDtos/PagerResponseDto.cs | 8 ++ .../ScraperDtos/Response/ScraperProductDto.cs | 14 +++ .../Models/RestAddress.cs | 1 + .../Digikala/GetDigikalProductResponseDto.cs | 65 ++++++++++ .../Digikala/GetDigikalProductsResponseDto.cs | 53 ++++++++ .../NetinaShop.Infrastructure.csproj | 5 + .../RestServices/IDigikalaRestApi.cs | 12 ++ .../RestServices/IRestApiWrapper.cs | 2 + .../Services/Scrapers/DigikalaScraper.cs | 113 ++++++++++++++++++ .../Services/UploadFileService.cs | 33 +++++ .../Handlers/Brands/GetBrandsQueryHandler.cs | 9 +- .../Products/CreateProductCommandHandler.cs | 3 + .../Products/GetProductQueryHandler.cs | 10 +- .../Products/GetProductsQueryHandler.cs | 14 ++- 24 files changed, 393 insertions(+), 35 deletions(-) create mode 100644 NetinaShop.Api/Controller/ScraperController.cs create mode 100644 NetinaShop.Core/Abstracts/IDigikalaScraper.cs create mode 100644 NetinaShop.Core/Abstracts/IUploadFileService.cs create mode 100644 NetinaShop.Domain/Dtos/ResponseDtos/GetProductResponseDto.cs create mode 100644 NetinaShop.Domain/Dtos/ResponseDtos/GetProductsResponseDto.cs create mode 100644 NetinaShop.Domain/Dtos/ResponseDtos/PagerResponseDto.cs create mode 100644 NetinaShop.Domain/Dtos/ScraperDtos/Response/ScraperProductDto.cs create mode 100644 NetinaShop.Infrastructure/Models/Scrapers/Digikala/GetDigikalProductResponseDto.cs create mode 100644 NetinaShop.Infrastructure/Models/Scrapers/Digikala/GetDigikalProductsResponseDto.cs create mode 100644 NetinaShop.Infrastructure/RestServices/IDigikalaRestApi.cs create mode 100644 NetinaShop.Infrastructure/Services/Scrapers/DigikalaScraper.cs create mode 100644 NetinaShop.Infrastructure/Services/UploadFileService.cs diff --git a/.version b/.version index 4ad4664..014c8fe 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -0.5.8.16 \ No newline at end of file +0.5.9.17 \ No newline at end of file diff --git a/NetinaShop.Api/Controller/FileController.cs b/NetinaShop.Api/Controller/FileController.cs index dade26b..b5a9771 100644 --- a/NetinaShop.Api/Controller/FileController.cs +++ b/NetinaShop.Api/Controller/FileController.cs @@ -22,24 +22,9 @@ public class FileController : ICarterModule public async Task GetFilesAsync([FromQuery]StorageFileType? fileType,[FromServices] IStorageService storageService, CancellationToken cancellationToken) => TypedResults.Ok(await storageService.GetStorageFiles(fileType: fileType ?? StorageFileType.Image)); - public async Task UploadFileAsync([FromBody] FileUploadRequest uploadRequest, [FromServices] IStorageService storageService, CancellationToken cancellationToken) - { - var bytes = Convert.FromBase64String(uploadRequest.StringBaseFile); - using var originalMedFileStream = new MemoryStream(bytes); - using var originalThumbFileStream = new MemoryStream(bytes); - using var thumbnailFileStream = new MemoryStream(); - using var mediumFileStream = new MemoryStream(); - await uploadRequest.ImageResize(originalMedFileStream, mediumFileStream, 1280); - await uploadRequest.ImageResize(originalThumbFileStream, thumbnailFileStream, 200); - var medFileName = await storageService.UploadObjectFromFileAsync(uploadRequest.FileName, $"{uploadRequest.FileUploadType.ToDisplay()}/Med", uploadRequest.ContentType, mediumFileStream); - await storageService.UploadObjectFromFileAsync(medFileName, $"{uploadRequest.FileUploadType.ToDisplay()}/Thumb", uploadRequest.ContentType, thumbnailFileStream, false); - var response = new FileUploadResponse - { - FileName = medFileName, - FileLocation = $"{uploadRequest.FileUploadType.ToDisplay()}/Med/{medFileName}", - FileUrl = $"https://storage.vesmook.com/{uploadRequest.FileUploadType.ToDisplay()}/Med/{medFileName}" - }; - return TypedResults.Ok(response); + public async Task UploadFileAsync([FromBody] FileUploadRequest uploadRequest, [FromServices] IUploadFileService uploadFileService, CancellationToken cancellationToken) + { + return TypedResults.Ok(await uploadFileService.UploadImageAsync(uploadRequest)); } } \ No newline at end of file diff --git a/NetinaShop.Api/Controller/ScraperController.cs b/NetinaShop.Api/Controller/ScraperController.cs new file mode 100644 index 0000000..75bca4b --- /dev/null +++ b/NetinaShop.Api/Controller/ScraperController.cs @@ -0,0 +1,25 @@ +namespace NetinaShop.Api.Controller; + +public class ScraperController : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + var group = app.NewVersionedApi("Scraper") + .MapGroup("api/scraper") + .RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser()); + + group.MapGet("digi", GetDigiProductsAsync) + .WithDisplayName("GetDigiProducts") + .HasApiVersion(1.0); + + group.MapPost("digi/{productId}", AddProductToShopAsync) + .WithDisplayName("AddProductToShop") + .HasApiVersion(1.0); + } + + public async Task GetDigiProductsAsync([FromQuery] string productName, [FromServices] IDigikalaScraper digikalaScraper, CancellationToken cancellationToken) + => TypedResults.Ok(await digikalaScraper.GetProductsByNameAsync(productName)); + + public async Task AddProductToShopAsync(string productId, [FromQuery] string productName, [FromServices] IDigikalaScraper digikalaScraper, CancellationToken cancellationToken) + => TypedResults.Ok(await digikalaScraper.AddProductToShopAsync(productId, productName,cancellationToken)); +} \ No newline at end of file diff --git a/NetinaShop.Api/NetinaShop.Api.csproj b/NetinaShop.Api/NetinaShop.Api.csproj index 7399e45..a5adaa6 100644 --- a/NetinaShop.Api/NetinaShop.Api.csproj +++ b/NetinaShop.Api/NetinaShop.Api.csproj @@ -6,8 +6,8 @@ enable true Linux - 0.5.7.15 - 0.5.7.15 + 0.5.9.17 + 0.5.9.17 diff --git a/NetinaShop.Core/Abstracts/IDigikalaScraper.cs b/NetinaShop.Core/Abstracts/IDigikalaScraper.cs new file mode 100644 index 0000000..6e43f88 --- /dev/null +++ b/NetinaShop.Core/Abstracts/IDigikalaScraper.cs @@ -0,0 +1,9 @@ +using NetinaShop.Domain.Dtos.ScraperDtos.Response; + +namespace NetinaShop.Core.Abstracts; + +public interface IDigikalaScraper : IScopedDependency +{ + public Task> GetProductsByNameAsync(string productName); + public Task AddProductToShopAsync(string productId, string productName , CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/NetinaShop.Core/Abstracts/IUploadFileService.cs b/NetinaShop.Core/Abstracts/IUploadFileService.cs new file mode 100644 index 0000000..3f8078c --- /dev/null +++ b/NetinaShop.Core/Abstracts/IUploadFileService.cs @@ -0,0 +1,6 @@ +namespace NetinaShop.Core.Abstracts; + +public interface IUploadFileService : IScopedDependency +{ + Task UploadImageAsync(FileUploadRequest uploadRequest); +} \ No newline at end of file diff --git a/NetinaShop.Core/NetinaShop.Core.csproj b/NetinaShop.Core/NetinaShop.Core.csproj index 7c8369f..2e00427 100644 --- a/NetinaShop.Core/NetinaShop.Core.csproj +++ b/NetinaShop.Core/NetinaShop.Core.csproj @@ -27,6 +27,7 @@ + diff --git a/NetinaShop.Domain/CommandQueries/Queries/ProductQueries.cs b/NetinaShop.Domain/CommandQueries/Queries/ProductQueries.cs index 3349f13..3c5b078 100644 --- a/NetinaShop.Domain/CommandQueries/Queries/ProductQueries.cs +++ b/NetinaShop.Domain/CommandQueries/Queries/ProductQueries.cs @@ -1,7 +1,7 @@ namespace NetinaShop.Domain.CommandQueries.Queries; -public sealed record GetProductQuery(Guid Id) : IRequest; +public sealed record GetProductQuery(Guid Id) : IRequest; public sealed record GetProductsQuery( Guid[]? BrandIds, bool? IsActive, @@ -11,4 +11,4 @@ public sealed record GetProductsQuery( QuerySortBy SortBy = QuerySortBy.None , Guid CategoryId = default , double MinPrice = -1 , - double MaxPrice = 0) : IRequest>; \ No newline at end of file + double MaxPrice = 0) : IRequest; \ No newline at end of file diff --git a/NetinaShop.Domain/Dtos/ResponseDtos/GetProductResponseDto.cs b/NetinaShop.Domain/Dtos/ResponseDtos/GetProductResponseDto.cs new file mode 100644 index 0000000..00c32d5 --- /dev/null +++ b/NetinaShop.Domain/Dtos/ResponseDtos/GetProductResponseDto.cs @@ -0,0 +1,6 @@ +namespace NetinaShop.Domain.Dtos.ResponseDtos; + +public class GetProductResponseDto +{ + public ProductLDto Product { get; set; } = new ProductLDto(); +} \ No newline at end of file diff --git a/NetinaShop.Domain/Dtos/ResponseDtos/GetProductsResponseDto.cs b/NetinaShop.Domain/Dtos/ResponseDtos/GetProductsResponseDto.cs new file mode 100644 index 0000000..e39e8b8 --- /dev/null +++ b/NetinaShop.Domain/Dtos/ResponseDtos/GetProductsResponseDto.cs @@ -0,0 +1,8 @@ +namespace NetinaShop.Domain.Dtos.ResponseDtos; + +public class GetProductsResponseDto +{ + public List Products { get; set; } = new List(); + + public PagerResponseDto Pager { get; set; } = new PagerResponseDto(); +} \ No newline at end of file diff --git a/NetinaShop.Domain/Dtos/ResponseDtos/PagerResponseDto.cs b/NetinaShop.Domain/Dtos/ResponseDtos/PagerResponseDto.cs new file mode 100644 index 0000000..b1aa41a --- /dev/null +++ b/NetinaShop.Domain/Dtos/ResponseDtos/PagerResponseDto.cs @@ -0,0 +1,8 @@ +namespace NetinaShop.Domain.Dtos.ResponseDtos; + +public class PagerResponseDto +{ + public int CurrentPage { get; set; } + public int TotalItems { get; set; } + public int TotalPage { get; set; } +} \ No newline at end of file diff --git a/NetinaShop.Domain/Dtos/ScraperDtos/Response/ScraperProductDto.cs b/NetinaShop.Domain/Dtos/ScraperDtos/Response/ScraperProductDto.cs new file mode 100644 index 0000000..6468870 --- /dev/null +++ b/NetinaShop.Domain/Dtos/ScraperDtos/Response/ScraperProductDto.cs @@ -0,0 +1,14 @@ +namespace NetinaShop.Domain.Dtos.ScraperDtos.Response; + +public class ScraperProductDto +{ + public string PersianName { get; set; } = string.Empty; + public string EnglishName { get; set; } = string.Empty; + public string Summery { get; set; } = string.Empty; + public double Cost { get; set; } + public string MainImage { get; set; } = string.Empty; + public string BrandName { get; set; } = string.Empty; + public string CategoryName { get; set; } = string.Empty; + public string ScraperId { get; set; } = string.Empty; + public string ScraperUrl { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/NetinaShop.Infrastructure/Models/RestAddress.cs b/NetinaShop.Infrastructure/Models/RestAddress.cs index a6a1f24..22f1fd1 100644 --- a/NetinaShop.Infrastructure/Models/RestAddress.cs +++ b/NetinaShop.Infrastructure/Models/RestAddress.cs @@ -4,4 +4,5 @@ public static class RestAddress { public static string BaseKaveNegar => "https://api.kavenegar.com/v1/"; public static string BaseZarinpal => "https://api.zarinpal.com/pg"; + public static string DigikalaApi => "https://api.digikala.com"; } \ No newline at end of file diff --git a/NetinaShop.Infrastructure/Models/Scrapers/Digikala/GetDigikalProductResponseDto.cs b/NetinaShop.Infrastructure/Models/Scrapers/Digikala/GetDigikalProductResponseDto.cs new file mode 100644 index 0000000..c36fd5f --- /dev/null +++ b/NetinaShop.Infrastructure/Models/Scrapers/Digikala/GetDigikalProductResponseDto.cs @@ -0,0 +1,65 @@ +namespace NetinaShop.Infrastructure.Models.Scrapers.Digikala; + +public class GetDigikalProductResponseDto +{ + + public int status { get; set; } + public Data data { get; set; } + + public class Attribute + { + public string title { get; set; } + public List values { get; set; } + } + + public class Data + { + public Product product { get; set; } + public Seo seo { get; set; } + } + + public class Seo + { + public string title { get; set; } + public string description { get; set; } + public Header header { get; set; } + } + public class Header + { + public string title { get; set; } + public string description { get; set; } + public string canonical_url { get; set; } + } + + public class Images + { + public Main main { get; set; } + } + + public class Main + { + public List storage_ids { get; set; } + public List url { get; set; } + public object thumbnail_url { get; set; } + public object temporary_id { get; set; } + public List webp_url { get; set; } + } + + public class Product + { + public int id { get; set; } + public string title_fa { get; set; } + public string title_en { get; set; } + public string status { get; set; } + public Images images { get; set; } + public List specifications { get; set; } + } + + public class Specification + { + public string title { get; set; } + public List attributes { get; set; } + } + + +} \ No newline at end of file diff --git a/NetinaShop.Infrastructure/Models/Scrapers/Digikala/GetDigikalProductsResponseDto.cs b/NetinaShop.Infrastructure/Models/Scrapers/Digikala/GetDigikalProductsResponseDto.cs new file mode 100644 index 0000000..7fcb0db --- /dev/null +++ b/NetinaShop.Infrastructure/Models/Scrapers/Digikala/GetDigikalProductsResponseDto.cs @@ -0,0 +1,53 @@ +namespace NetinaShop.Infrastructure.Models.Scrapers.Digikala; + +public class GetDigikalProductsResponseDto +{ + + public int status { get; set; } + public GetDigikalProductsResponseDtoData data { get; set; } + + public class GetDigikalProductsResponseDtoData + { + public List products { get; set; } + } + + public class GetDigikalProductsResponseDtoImages + { + public GetDigikalProductsResponseDtoMain main { get; set; } + } + + + public class GetDigikalProductsResponseDtoMain + { + public List storage_ids { get; set; } + public List url { get; set; } + public object thumbnail_url { get; set; } + public object temporary_id { get; set; } + public List webp_url { get; set; } + } + + public class GetDigikalProductsResponseDtoProduct + { + public int id { get; set; } + public string title_fa { get; set; } + public string title_en { get; set; } + public GetDigikalProductsResponseDtoUrl url { get; set; } + public GetDigikalProductsResponseDtoImages images { get; set; } + //public GetDigikalProductsResponseDtoVarient default_variant { get; set; } + } + public class GetDigikalProductsResponseDtoVarient + { + //public GetDigikalProductsResponseDtoPrice price { get; set; } + } + + public class GetDigikalProductsResponseDtoPrice + { + //public string rrp_price { get; set; } + } + public class GetDigikalProductsResponseDtoUrl + { + public string uri { get; set; } + } + + +} \ No newline at end of file diff --git a/NetinaShop.Infrastructure/NetinaShop.Infrastructure.csproj b/NetinaShop.Infrastructure/NetinaShop.Infrastructure.csproj index 2a847a6..ff37125 100644 --- a/NetinaShop.Infrastructure/NetinaShop.Infrastructure.csproj +++ b/NetinaShop.Infrastructure/NetinaShop.Infrastructure.csproj @@ -35,4 +35,9 @@ + + + + + diff --git a/NetinaShop.Infrastructure/RestServices/IDigikalaRestApi.cs b/NetinaShop.Infrastructure/RestServices/IDigikalaRestApi.cs new file mode 100644 index 0000000..b6bcc5d --- /dev/null +++ b/NetinaShop.Infrastructure/RestServices/IDigikalaRestApi.cs @@ -0,0 +1,12 @@ +using NetinaShop.Infrastructure.Models.Scrapers.Digikala; + +namespace NetinaShop.Infrastructure.RestServices; + +public interface IDigikalaRestApi +{ + [Get("/v1/search/")] + Task SearchProductAsync([Query] string q); + + [Get("/v1/product/{productId}/")] + Task GetProductAsync(string productId); +} \ No newline at end of file diff --git a/NetinaShop.Infrastructure/RestServices/IRestApiWrapper.cs b/NetinaShop.Infrastructure/RestServices/IRestApiWrapper.cs index 843831c..2c5dfa8 100644 --- a/NetinaShop.Infrastructure/RestServices/IRestApiWrapper.cs +++ b/NetinaShop.Infrastructure/RestServices/IRestApiWrapper.cs @@ -6,10 +6,12 @@ public interface IRestApiWrapper : IScopedDependency { IKaveNegarRestApi KaveNegarRestApi { get; } IZarinpalRestApi ZarinpalRestApi { get; } + IDigikalaRestApi DigikalaRestApi { get; } } public class RestApiWrapper : IRestApiWrapper { public IKaveNegarRestApi KaveNegarRestApi => RestService.For(RestAddress.BaseKaveNegar); public IZarinpalRestApi ZarinpalRestApi => RestService.For(RestAddress.BaseZarinpal); + public IDigikalaRestApi DigikalaRestApi => RestService.For(RestAddress.DigikalaApi); } \ No newline at end of file diff --git a/NetinaShop.Infrastructure/Services/Scrapers/DigikalaScraper.cs b/NetinaShop.Infrastructure/Services/Scrapers/DigikalaScraper.cs new file mode 100644 index 0000000..639724f --- /dev/null +++ b/NetinaShop.Infrastructure/Services/Scrapers/DigikalaScraper.cs @@ -0,0 +1,113 @@ +using NetinaShop.Domain.CommandQueries.Commands; +using NetinaShop.Domain.Dtos.ScraperDtos.Response; +using NetinaShop.Domain.Dtos.SmallDtos; +using NetinaShop.Domain.Entities.Products; +using NetinaShop.Repository.Repositories.Base.Contracts; +using System.Linq; +using MediatR; +using Microsoft.EntityFrameworkCore; +using NetinaShop.Domain.Entities.Brands; +using NetinaShop.Domain.Entities.ProductCategories; + +namespace NetinaShop.Infrastructure.Services.Scrapers; + +public class DigikalaScraper : IDigikalaScraper +{ + private readonly IRestApiWrapper _apiWrapper; + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly IMediator _mediator; + private readonly IUploadFileService _uploadFileService; + + public DigikalaScraper(IRestApiWrapper apiWrapper, IRepositoryWrapper repositoryWrapper,IMediator mediator, IUploadFileService uploadFileService) + { + _apiWrapper = apiWrapper; + _repositoryWrapper = repositoryWrapper; + _mediator = mediator; + _uploadFileService = uploadFileService; + } + public async Task> GetProductsByNameAsync(string productName) + { + var products = await _apiWrapper.DigikalaRestApi.SearchProductAsync(productName); + return products.data.products.Select(s => new ScraperProductDto + { + PersianName = s.title_fa, + EnglishName = s.title_en, + MainImage = s.images.main.url.First(), + //Cost = long.TryParse(s.default_variant.price.rrp_price,out long result) ? result : 0, + ScraperId = s.id.ToString(), + ScraperUrl = $"https://digikala.com/{s.url.uri}" + }).ToList(); + } + + public async Task AddProductToShopAsync(string productId, string productName, CancellationToken cancellationToken = default) + { + var response = await _apiWrapper.DigikalaRestApi.GetProductAsync(productId); + var digiProduct = response.data; + var dbProduct = await _repositoryWrapper.SetRepository() + .TableNoTracking + .FirstOrDefaultAsync(p => p.PersianName.ToLower().Trim().Contains(productName.ToLower().Trim()), cancellationToken); + + var specifications = new List(); + foreach (var specification in digiProduct.product.specifications) + { + foreach (var attribute in specification.attributes) + { + specifications.Add(new SpecificationSDto { Value = string.Join(",", attribute.values), Title = attribute.title }); + } + } + + using var httClient = new HttpClient(); + var imageBytes = await httClient.GetByteArrayAsync(digiProduct.product.images.main.url.FirstOrDefault(), cancellationToken); + var imageBase64 = Convert.ToBase64String(imageBytes); + var uploadFile = new FileUploadRequest + { + StringBaseFile = imageBase64, + FileName = digiProduct.product.title_fa.Replace(" ", "_") + ".jpg", + FileUploadType = FileUploadType.Image, + ContentType = "image/jpeg" + }; + var uploadResponse = await _uploadFileService.UploadImageAsync(uploadFile); + var files = new List + { + new StorageFileSDto + { + FileLocation = uploadResponse.FileLocation, + FileName = uploadResponse.FileName, + IsPrimary = true, + } + }; + if (dbProduct != null) + { + var request = new UpdateProductCommand(dbProduct.Id, productName, digiProduct.product.title_en, + digiProduct.seo.description, + dbProduct.ExpertCheck, dbProduct.Tags, dbProduct.Warranty, dbProduct.BeDisplayed, dbProduct.Cost, + dbProduct.PackingCost, dbProduct.Stock, dbProduct.HasExpressDelivery + , dbProduct.MaxOrderCount, false, dbProduct.BrandId, dbProduct.CategoryId, new DiscountSDto(), specifications, files); + await _mediator.Send(request, cancellationToken); + } + else + { + var nonBrand = await _repositoryWrapper.SetRepository() + .TableNoTracking + .FirstOrDefaultAsync(b => b.Name == "بدون برند", cancellationToken); + if (nonBrand == null) + throw new AppException("NoneBrand is not exist"); + + var nonCat = await _repositoryWrapper.SetRepository() + .TableNoTracking + .FirstOrDefaultAsync(b => b.Name == "دسته بندی نشده", cancellationToken); + if (nonCat == null) + throw new AppException("NoneCategory is not exist"); + + + var request = new CreateProductCommand(productName, digiProduct.product.title_en, + digiProduct.seo.description, + string.Empty, string.Empty, string.Empty,true, 0, + 0, 0, false + , 5, false, nonBrand.Id, nonCat.Id, new DiscountSDto(), specifications, files); + await _mediator.Send(request, cancellationToken); + } + + return true; + } +} \ No newline at end of file diff --git a/NetinaShop.Infrastructure/Services/UploadFileService.cs b/NetinaShop.Infrastructure/Services/UploadFileService.cs new file mode 100644 index 0000000..1e5bf38 --- /dev/null +++ b/NetinaShop.Infrastructure/Services/UploadFileService.cs @@ -0,0 +1,33 @@ +using NetinaShop.Core.Utilities; + +namespace NetinaShop.Infrastructure.Services; + +public class UploadFileService : IUploadFileService +{ + private readonly IStorageService _storageService; + + public UploadFileService(IStorageService storageService) + { + _storageService = storageService; + } + public async Task UploadImageAsync(FileUploadRequest uploadRequest) + { + var bytes = Convert.FromBase64String(uploadRequest.StringBaseFile); + using var originalMedFileStream = new MemoryStream(bytes); + using var originalThumbFileStream = new MemoryStream(bytes); + using var thumbnailFileStream = new MemoryStream(); + using var mediumFileStream = new MemoryStream(); + + await uploadRequest.ImageResize(originalMedFileStream, mediumFileStream, 1280); + await uploadRequest.ImageResize(originalThumbFileStream, thumbnailFileStream, 200); + var medFileName = await _storageService.UploadObjectFromFileAsync(uploadRequest.FileName, $"{uploadRequest.FileUploadType.ToDisplay()}/Med", uploadRequest.ContentType, mediumFileStream); + await _storageService.UploadObjectFromFileAsync(medFileName, $"{uploadRequest.FileUploadType.ToDisplay()}/Thumb", uploadRequest.ContentType, thumbnailFileStream, false); + var response = new FileUploadResponse + { + FileName = medFileName, + FileLocation = $"{uploadRequest.FileUploadType.ToDisplay()}/Med/{medFileName}", + FileUrl = $"https://storage.vesmook.com/{uploadRequest.FileUploadType.ToDisplay()}/Med/{medFileName}" + }; + return response; + } +} \ No newline at end of file diff --git a/NetinaShop.Repository/Handlers/Brands/GetBrandsQueryHandler.cs b/NetinaShop.Repository/Handlers/Brands/GetBrandsQueryHandler.cs index 7b3810c..6cf107b 100644 --- a/NetinaShop.Repository/Handlers/Brands/GetBrandsQueryHandler.cs +++ b/NetinaShop.Repository/Handlers/Brands/GetBrandsQueryHandler.cs @@ -19,9 +19,12 @@ public class GetBrandsQueryHandler : IRequestHandler brands = new List(); if (request.CategoryId != default) { - var products = await _mediator.Send(new GetProductsQuery(BrandIds: null,SpecialOffer: null, Page:0, SortBy: QuerySortBy.None,CategoryId: request.CategoryId, IsActive : null), - cancellationToken); - var brandGrouped = products.GroupBy(p => p.BrandId); + //var products = await _mediator.Send(new GetProductsQuery(BrandIds: null,SpecialOffer: null, Page:0, SortBy: QuerySortBy.None,CategoryId: request.CategoryId, IsActive : null), + // cancellationToken); + var brandGrouped = _repositoryWrapper.SetRepository() + .TableNoTracking + .Where(p => p.CategoryId == request.CategoryId) + .GroupBy(p=>p.BrandId); foreach (var grouping in brandGrouped) { if (grouping.Key != default) diff --git a/NetinaShop.Repository/Handlers/Products/CreateProductCommandHandler.cs b/NetinaShop.Repository/Handlers/Products/CreateProductCommandHandler.cs index 06d5d52..6fa5514 100644 --- a/NetinaShop.Repository/Handlers/Products/CreateProductCommandHandler.cs +++ b/NetinaShop.Repository/Handlers/Products/CreateProductCommandHandler.cs @@ -13,6 +13,7 @@ public class CreateProductCommandHandler : IRequestHandler Handle(CreateProductCommand request, CancellationToken cancellationToken) { + var ent = Product.Create(request.PersianName, request.EnglishName, request.Summery, request.ExpertCheck, request.Tags, request.Warranty,request.BeDisplayed,request.Cost,request.PackingCost, request.HasExpressDelivery, @@ -31,6 +32,8 @@ public class CreateProductCommandHandler : IRequestHandler().Add(ent); await _repositoryWrapper.SaveChangesAsync(cancellationToken); diff --git a/NetinaShop.Repository/Handlers/Products/GetProductQueryHandler.cs b/NetinaShop.Repository/Handlers/Products/GetProductQueryHandler.cs index a3f1bef..677984d 100644 --- a/NetinaShop.Repository/Handlers/Products/GetProductQueryHandler.cs +++ b/NetinaShop.Repository/Handlers/Products/GetProductQueryHandler.cs @@ -2,7 +2,7 @@ namespace NetinaShop.Repository.Handlers.Products; -public class GetProductQueryHandler : IRequestHandler +public class GetProductQueryHandler : IRequestHandler { private readonly IRepositoryWrapper _repositoryWrapper; @@ -10,7 +10,7 @@ public class GetProductQueryHandler : IRequestHandler Handle(GetProductQuery request, CancellationToken cancellationToken) + public async Task Handle(GetProductQuery request, CancellationToken cancellationToken) { var ent = await _repositoryWrapper.SetRepository().TableNoTracking .Where(b => b.Id == request.Id) @@ -33,6 +33,10 @@ public class GetProductQueryHandler : IRequestHandler> +public class GetProductsQueryHandler : IRequestHandler { private readonly IRepositoryWrapper _repositoryWrapper; private readonly IMediator _mediator; @@ -15,8 +12,9 @@ public class GetProductsQueryHandler : IRequestHandler> Handle(GetProductsQuery request, CancellationToken cancellationToken) + public async Task Handle(GetProductsQuery request, CancellationToken cancellationToken) { + var response = new GetProductsResponseDto(); var products = _repositoryWrapper.SetRepository().TableNoTracking; if (request.IsActive != null) products = products.Where(p => p.IsEnable == request.IsActive); @@ -64,6 +62,9 @@ public class GetProductsQueryHandler : IRequestHandler productSDtos = await products .Skip(request.Page * 20) @@ -76,6 +77,7 @@ public class GetProductsQueryHandler : IRequestHandler