feat : complete review entity

complete review controller and CQRS , change service handlers to Core project
release
Amir Hossein Khademi 2024-01-01 16:18:49 +03:30
parent 0a1c080581
commit ef97797c5e
32 changed files with 438 additions and 4226 deletions

View File

@ -1,4 +1,6 @@
namespace NetinaShop.Api.Controller;
using NetinaShop.Domain.Enums;
namespace NetinaShop.Api.Controller;
public class ProductController : ICarterModule
{
@ -28,8 +30,8 @@ public class ProductController : ICarterModule
}
// GET:Get All Entity
public async Task<IResult> GetAllAsync([FromQuery] int page, IMediator mediator, CancellationToken cancellationToken)
=> TypedResults.Ok(await mediator.Send(new GetProductsQuery(page),cancellationToken));
public async Task<IResult> GetAllAsync([FromQuery] int page, [FromQuery] QuerySortBy? sortBy,[FromQuery] Guid? categoryId , [FromQuery]Guid? brandId , [FromQuery]double? minPrice , [FromQuery] double? maxPrice, IMediator mediator, CancellationToken cancellationToken)
=> TypedResults.Ok(await mediator.Send(new GetProductsQuery(page,SortBy: sortBy ?? 0 , CategoryId: categoryId ?? default , BrandId: brandId ?? default , MinPrice: minPrice ?? -1 , MaxPrice:maxPrice ?? 0),cancellationToken));
// GET:Get An Entity By Id
public async Task<IResult> GetAsync(Guid id, IMediator mediator,CancellationToken cancellationToken)

View File

@ -0,0 +1,46 @@
namespace NetinaShop.Api.Controller;
public class ProductReviewController : ICarterModule
{
public void AddRoutes(IEndpointRouteBuilder app)
{
var group = app.NewVersionedApi("ProductReview")
.MapGroup("product/review")
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser());
group.MapGet("{id}", GetAsync)
.WithDisplayName("GetOneAsync")
.HasApiVersion(1.0);
group.MapGet("", GetAllAsync)
.WithDisplayName("GetAllAsync")
.HasApiVersion(1.0);
group.MapPost("", PostAsync)
.WithDisplayName("PostReview")
.HasApiVersion(1.0);
group.MapPut("confirm/{id}", ConfirmAsync)
.WithDisplayName("ConfirmAsync")
.HasApiVersion(1.0);
group.MapDelete("{id}", DeleteAsync)
.WithDisplayName("DeleteAsync")
.HasApiVersion(1.0);
}
public async Task<IResult> GetAllAsync([FromQuery] int page, IMediator mediator, CancellationToken cancellationToken)
=> TypedResults.Ok(await mediator.Send(new GetReviewsQuery(page), cancellationToken));
public async Task<IResult> GetAsync(Guid id, IMediator mediator, CancellationToken cancellationToken)
=> TypedResults.Ok(await mediator.Send(new GetReviewQuery(id), cancellationToken));
public async Task<IResult> PostAsync(CreateReviewCommand request, IMediator mediator, CancellationToken cancellationToken)
=> TypedResults.Ok(await mediator.Send(request, cancellationToken));
public async Task<IResult> ConfirmAsync(Guid id, IMediator mediator, CancellationToken cancellationToken)
=> TypedResults.Ok(await mediator.Send(new ConfirmReviewCommand(id), cancellationToken));
public async Task<IResult> DeleteAsync(Guid id, IMediator mediator, CancellationToken cancellationToken)
=> TypedResults.Ok(await mediator.Send(new DeleteReviewCommand(id), cancellationToken));
}

View File

@ -5,7 +5,7 @@ public class ShippingController : ICarterModule
public virtual void AddRoutes(IEndpointRouteBuilder app)
{
var group = app.NewVersionedApi("Warehouse")
var group = app.NewVersionedApi("WarehouseShipping")
.MapGroup($"api/warehouse/shipping")
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser());

View File

@ -1,4 +1,4 @@
namespace NetinaShop.Repository.Handlers.Discounts;
namespace NetinaShop.Core.EntityServices.DiscountHandlers;
public class CalculateDiscountCommandHandler : IRequestHandler<CalculateDiscountCommand , double>
{

View File

@ -1,6 +1,4 @@
using NetinaShop.Domain.Entities.Orders;
namespace NetinaShop.Repository.Handlers.OrderBags;
namespace NetinaShop.Core.EntityServices.OrderBagHandlers;
public class AddToOrderBagCommandHandler : IRequestHandler<AddToOrderBagCommand,bool>
{

View File

@ -1,6 +1,4 @@
using NetinaShop.Domain.Entities.Orders;
namespace NetinaShop.Repository.Handlers.OrderBags;
namespace NetinaShop.Core.EntityServices.OrderBagHandlers;
public class GetUserOrderBagQueryHandler : IRequestHandler<GetUserOrderBagQuery,Order>
{

View File

@ -1,6 +1,4 @@
using Order = NetinaShop.Domain.Entities.Orders.Order;
namespace NetinaShop.Repository.Handlers.OrderBags;
namespace NetinaShop.Core.EntityServices.OrderBagHandlers;
public class RemoveFromOrderBagCommandHandler : IRequestHandler<RemoveFromOrderBagCommand,bool>
{

View File

@ -1,6 +1,4 @@
using NetinaShop.Domain.Entities.Orders;
namespace NetinaShop.Repository.Handlers.OrderBags;
namespace NetinaShop.Core.EntityServices.OrderBagHandlers;
public class SubmitDiscountCommandHandler : IRequestHandler<SubmitDiscountCommand,bool>
{

View File

@ -1,7 +1,6 @@
using NetinaShop.Domain.Entities.Orders;
using NetinaShop.Domain.Entities.Warehouses;
using NetinaShop.Domain.Entities.Warehouses;
namespace NetinaShop.Repository.Handlers.OrderBags;
namespace NetinaShop.Core.EntityServices.OrderBagHandlers;
public class SubmitOrderDeliveryCommandHandler : IRequestHandler<SubmitOrderDeliveryCommand,bool>
{

View File

@ -1,6 +1,4 @@
using NetinaShop.Domain.Entities.Orders;
namespace NetinaShop.Repository.Handlers.OrderBags;
namespace NetinaShop.Core.EntityServices.OrderBagHandlers;
public class SubmitOrderPaymentCommandHandler : IRequestHandler<SubmitOrderPaymentCommand , SubmitOrderPaymentResponseDto>
{

View File

@ -1,7 +1,4 @@
using Microsoft.IdentityModel.Tokens;
using NetinaShop.Domain.Entities.Orders;
namespace NetinaShop.Repository.Handlers.Orders;
namespace NetinaShop.Core.EntityServices.OrderHandlers;
public class CalculateOrderCommandHandler : IRequestHandler<CalculateOrderCommand,Order>
{

View File

@ -0,0 +1,23 @@
namespace NetinaShop.Core.EntityServices.ReviewHandlers;
public class ConfirmReviewCommandHandler : IRequestHandler<ConfirmReviewCommand , bool>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public ConfirmReviewCommandHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<bool> Handle(ConfirmReviewCommand request, CancellationToken cancellationToken)
{
var review = await _repositoryWrapper.SetRepository<Review>().TableNoTracking
.FirstOrDefaultAsync(r => r.Id == request.Id, cancellationToken);
if (review == null)
throw new AppException("Review not found", ApiResultStatusCode.NotFound);
review.ConfirmReview();
_repositoryWrapper.SetRepository<Review>().Update(review);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return true;
}
}

View File

@ -24,12 +24,14 @@
<ItemGroup>
<Folder Include="Abstracts\" />
<Folder Include="BaseServices\Abstracts\" />
<Folder Include="EntityServices\ReviewHandlers\" />
<Folder Include="Models\Api\" />
</ItemGroup>
<ItemGroup>
<Using Include="Mapster" />
<Using Include="MediatR" />
<Using Include="Microsoft.AspNetCore.Identity" />
<Using Include="Microsoft.AspNetCore.Mvc" />
<Using Include="Microsoft.EntityFrameworkCore" />
@ -43,9 +45,14 @@
<Using Include="NetinaShop.Core.BaseServices.Abstracts" />
<Using Include="NetinaShop.Core.CoreServices.Abstracts" />
<Using Include="NetinaShop.Core.EntityServices.Abstracts" />
<Using Include="NetinaShop.Domain.CommandQueries.Commands" />
<Using Include="NetinaShop.Domain.CommandQueries.Queries" />
<Using Include="NetinaShop.Domain.Dtos.RequestDtos" />
<Using Include="NetinaShop.Domain.Dtos.ResponseDtos" />
<Using Include="NetinaShop.Domain.Dtos.SmallDtos" />
<Using Include="NetinaShop.Domain.Entities.Discounts" />
<Using Include="NetinaShop.Domain.Entities.Orders" />
<Using Include="NetinaShop.Domain.Entities.Products" />
<Using Include="NetinaShop.Domain.Entities.Users" />
<Using Include="NetinaShop.Domain.Enums" />
<Using Include="NetinaShop.Domain.Mappers" />

View File

@ -0,0 +1,6 @@
namespace NetinaShop.Domain.CommandQueries.Commands;
public sealed record CreateReviewCommand(string Title, string Comment, float Rate, bool IsBuyer, Guid ProductId, Guid UserId) : IRequest<ReviewSDto>;
public sealed record UpdateReviewCommand(Guid Id,string Title, string Comment, float Rate, bool IsBuyer, Guid ProductId, Guid UserId): IRequest<bool>;
public sealed record ConfirmReviewCommand(Guid Id) : IRequest<bool>;
public sealed record DeleteReviewCommand(Guid Id) : IRequest<bool>;

View File

@ -2,4 +2,4 @@
public sealed record GetProductQuery(Guid Id) : IRequest<ProductLDto>;
public sealed record GetProductsQuery(int Page = 0) : IRequest<List<ProductSDto>>;
public sealed record GetProductsQuery(int Page = 0 , QuerySortBy SortBy = QuerySortBy.None , Guid CategoryId = default , Guid BrandId = default , double MinPrice = -1 , double MaxPrice = 0) : IRequest<List<ProductSDto>>;

View File

@ -0,0 +1,4 @@
namespace NetinaShop.Domain.CommandQueries.Queries;
public record GetReviewsQuery(int Page = 0) : IRequest<List<ReviewSDto>>;
public record GetReviewQuery(Guid Id) : IRequest<ReviewLDto>;

View File

@ -0,0 +1,12 @@
namespace NetinaShop.Domain.Dtos.LargDtos;
public class ReviewLDto : BaseDto<ReviewLDto,Review>
{
public string Title { get; set; } = string.Empty;
public string Comment { get; set; } = string.Empty;
public float Rate { get; set; }
public bool IsBuyer { get; set; }
public bool IsConfirmed { get; set; }
public Guid ProductId { get; set; }
public Guid UserId { get; set; }
}

View File

@ -2,10 +2,29 @@
public partial class Product
{
public static Product Create(string persianName, string englishName, string summery, string expertCheck, string tags, string warranty, bool beDisplayed, double cost, double packingCost, Guid brandId,Guid categoryId)
public static Product Create(string persianName, string englishName, string summery, string expertCheck, string tags, string warranty, bool beDisplayed, double cost, double packingCost,
int reviewCount,
float reviewRate,
int viewed,
Guid brandId,
Guid categoryId)
{
return new Product(persianName, englishName, summery, expertCheck, tags, warranty, beDisplayed,cost,packingCost, brandId,categoryId);
return new Product(persianName, englishName, summery, expertCheck, tags, warranty, beDisplayed,cost, packingCost, reviewCount, reviewRate, viewed, brandId,categoryId);
}
public void AddRate(float rate)
{
Rate = ((Rate * ReviewCount) + rate) / (ReviewCount + 1);
ReviewCount++;
}
public void RemoveRate(float rate)
{
Rate = ((Rate * ReviewCount) - rate) / (ReviewCount - 1);
ReviewCount--;
}
public ProductStorageFile AddFile(string name, string fileLocation, string fileName, bool isHeader, bool isPrimary, StorageFileType fileType)
{
var ent = ProductStorageFile.Create(name, fileLocation, fileName, isHeader, isPrimary, fileType, Id);
@ -37,6 +56,8 @@ public partial class Review
return new Review(title, comment, rate, isBuyer, productId, userId);
}
public void ConfirmReview()
=> IsConfirmed = true;
}
public partial class Specification

View File

@ -10,7 +10,20 @@ public partial class Product : ApiEntity
}
public Product(string persianName, string englishName, string summery, string expertCheck, string tags, string warranty, bool beDisplayed, double cost, double packingCost, Guid brandId, Guid categoryId)
public Product(string persianName,
string englishName,
string summery,
string expertCheck,
string tags,
string warranty,
bool beDisplayed,
double cost,
double packingCost,
int reviewCount,
float rate,
int viewed,
Guid brandId,
Guid categoryId)
{
PersianName = persianName;
EnglishName = englishName;
@ -23,21 +36,27 @@ public partial class Product : ApiEntity
PackingCost = packingCost;
BrandId = brandId;
CategoryId = categoryId;
ReviewCount = reviewCount;
Rate = rate;
Viewed = viewed;
}
public string PersianName { get; internal set; } = string.Empty;
public string EnglishName { get; internal set; } = string.Empty;
public string Summery { get; internal set; } = string.Empty;
public string ExpertCheck { get; internal set; } = string.Empty;
public string Tags { get; internal set; } = string.Empty;
public string Warranty { get; set; } = string.Empty;
public double Cost { get; set; }
public bool IsEnable { get; set; }
public bool BeDisplayed { get; set; }
public double PackingCost { get; set; }
public string Warranty { get; internal set; } = string.Empty;
public double Cost { get; internal set; }
public bool IsEnable { get; internal set; }
public bool BeDisplayed { get; internal set; }
public double PackingCost { get; internal set; }
public float Rate { get; internal set; }
public int ReviewCount { get; internal set; }
public int Viewed { get; internal set; }
public Guid BrandId { get; internal set; }
public Brand? Brand { get; set; }
public Brand? Brand { get; internal set; }
public Guid CategoryId { get; internal set; }
public Category? Category { get; internal set; }

View File

@ -23,6 +23,7 @@ public partial class Review : ApiEntity
public string Comment { get; internal set; } = string.Empty;
public float Rate { get; internal set; }
public bool IsBuyer { get; internal set; }
public bool IsConfirmed { get; internal set; }
public Guid ProductId { get; internal set; }
public Product? Product { get; internal set; }

View File

@ -0,0 +1,15 @@
namespace NetinaShop.Domain.Enums;
public enum QuerySortBy
{
[Display(Name = "هیچکدام")]
None = 0,
[Display(Name = "پربازدید ترین")]
MostViewed = 1,
[Display(Name = "محبوب ترین")]
MostPopular = 2,
[Display(Name = "گرانترین")]
MostExpensive = 3,
[Display(Name = "ارزانترین")]
Cheapest = 4,
}

View File

@ -1,5 +1,6 @@
using System;
using System.Linq.Expressions;
using NetinaShop.Domain.Dtos.LargDtos;
using NetinaShop.Domain.Dtos.SmallDtos;
using NetinaShop.Domain.Entities.Products;
@ -7,7 +8,7 @@ namespace NetinaShop.Domain.Mappers
{
public static partial class ReviewMapper
{
public static Review AdaptToReview(this ReviewSDto p1)
public static Review AdaptToReview(this ReviewLDto p1)
{
return p1 == null ? null : new Review()
{
@ -15,12 +16,13 @@ namespace NetinaShop.Domain.Mappers
Comment = p1.Comment,
Rate = p1.Rate,
IsBuyer = p1.IsBuyer,
IsConfirmed = p1.IsConfirmed,
ProductId = p1.ProductId,
UserId = p1.UserId,
Id = p1.Id
};
}
public static Review AdaptTo(this ReviewSDto p2, Review p3)
public static Review AdaptTo(this ReviewLDto p2, Review p3)
{
if (p2 == null)
{
@ -32,52 +34,139 @@ namespace NetinaShop.Domain.Mappers
result.Comment = p2.Comment;
result.Rate = p2.Rate;
result.IsBuyer = p2.IsBuyer;
result.IsConfirmed = p2.IsConfirmed;
result.ProductId = p2.ProductId;
result.UserId = p2.UserId;
result.Id = p2.Id;
return result;
}
public static ReviewSDto AdaptToSDto(this Review p4)
public static Expression<Func<ReviewLDto, Review>> ProjectToReview => p4 => new Review()
{
return p4 == null ? null : new ReviewSDto()
Title = p4.Title,
Comment = p4.Comment,
Rate = p4.Rate,
IsBuyer = p4.IsBuyer,
IsConfirmed = p4.IsConfirmed,
ProductId = p4.ProductId,
UserId = p4.UserId,
Id = p4.Id
};
public static ReviewLDto AdaptToLDto(this Review p5)
{
return p5 == null ? null : new ReviewLDto()
{
Title = p4.Title,
Comment = p4.Comment,
Rate = p4.Rate,
IsBuyer = p4.IsBuyer,
ProductId = p4.ProductId,
UserId = p4.UserId,
Id = p4.Id
Title = p5.Title,
Comment = p5.Comment,
Rate = p5.Rate,
IsBuyer = p5.IsBuyer,
IsConfirmed = p5.IsConfirmed,
ProductId = p5.ProductId,
UserId = p5.UserId,
Id = p5.Id
};
}
public static ReviewSDto AdaptTo(this Review p5, ReviewSDto p6)
public static ReviewLDto AdaptTo(this Review p6, ReviewLDto p7)
{
if (p5 == null)
if (p6 == null)
{
return null;
}
ReviewSDto result = p6 ?? new ReviewSDto();
ReviewLDto result = p7 ?? new ReviewLDto();
result.Title = p5.Title;
result.Comment = p5.Comment;
result.Rate = p5.Rate;
result.IsBuyer = p5.IsBuyer;
result.ProductId = p5.ProductId;
result.UserId = p5.UserId;
result.Id = p5.Id;
result.Title = p6.Title;
result.Comment = p6.Comment;
result.Rate = p6.Rate;
result.IsBuyer = p6.IsBuyer;
result.IsConfirmed = p6.IsConfirmed;
result.ProductId = p6.ProductId;
result.UserId = p6.UserId;
result.Id = p6.Id;
return result;
}
public static Expression<Func<Review, ReviewSDto>> ProjectToSDto => p7 => new ReviewSDto()
public static Expression<Func<Review, ReviewLDto>> ProjectToLDto => p8 => new ReviewLDto()
{
Title = p7.Title,
Comment = p7.Comment,
Rate = p7.Rate,
IsBuyer = p7.IsBuyer,
ProductId = p7.ProductId,
UserId = p7.UserId,
Id = p7.Id
Title = p8.Title,
Comment = p8.Comment,
Rate = p8.Rate,
IsBuyer = p8.IsBuyer,
IsConfirmed = p8.IsConfirmed,
ProductId = p8.ProductId,
UserId = p8.UserId,
Id = p8.Id
};
public static Review AdaptToReview(this ReviewSDto p9)
{
return p9 == null ? null : new Review()
{
Title = p9.Title,
Comment = p9.Comment,
Rate = p9.Rate,
IsBuyer = p9.IsBuyer,
ProductId = p9.ProductId,
UserId = p9.UserId,
Id = p9.Id
};
}
public static Review AdaptTo(this ReviewSDto p10, Review p11)
{
if (p10 == null)
{
return null;
}
Review result = p11 ?? new Review();
result.Title = p10.Title;
result.Comment = p10.Comment;
result.Rate = p10.Rate;
result.IsBuyer = p10.IsBuyer;
result.ProductId = p10.ProductId;
result.UserId = p10.UserId;
result.Id = p10.Id;
return result;
}
public static ReviewSDto AdaptToSDto(this Review p12)
{
return p12 == null ? null : new ReviewSDto()
{
Title = p12.Title,
Comment = p12.Comment,
Rate = p12.Rate,
IsBuyer = p12.IsBuyer,
ProductId = p12.ProductId,
UserId = p12.UserId,
Id = p12.Id
};
}
public static ReviewSDto AdaptTo(this Review p13, ReviewSDto p14)
{
if (p13 == null)
{
return null;
}
ReviewSDto result = p14 ?? new ReviewSDto();
result.Title = p13.Title;
result.Comment = p13.Comment;
result.Rate = p13.Rate;
result.IsBuyer = p13.IsBuyer;
result.ProductId = p13.ProductId;
result.UserId = p13.UserId;
result.Id = p13.Id;
return result;
}
public static Expression<Func<Review, ReviewSDto>> ProjectToSDto => p15 => new ReviewSDto()
{
Title = p15.Title,
Comment = p15.Comment,
Rate = p15.Rate,
IsBuyer = p15.IsBuyer,
ProductId = p15.ProductId,
UserId = p15.UserId,
Id = p15.Id
};
}
}

View File

@ -12,7 +12,8 @@ public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand,
public async Task<ProductLDto> 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.BrandId,request.CategoryId);
request.Tags, request.Warranty,request.BeDisplayed,request.Cost,request.PackingCost,0,0,0,
request.BrandId,request.CategoryId);
foreach (var specification in request.Specifications)
{
ent.AddSpecification(specification.Title, specification.Detail, specification.Value,

View File

@ -10,8 +10,35 @@ public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, List<Pr
}
public async Task<List<ProductSDto>> Handle(GetProductsQuery request, CancellationToken cancellationToken)
{
return await _repositoryWrapper.SetRepository<Product>().TableNoTracking
.OrderByDescending(b => b.CreatedAt).Skip(request.Page * 10)
var products = _repositoryWrapper.SetRepository<Product>().TableNoTracking;
if (request.CategoryId != default)
products = products.Where(p => p.CategoryId == request.CategoryId);
if (request.BrandId != default)
products = products.Where(p => p.BrandId == request.BrandId);
if (request.MinPrice > -1)
products = products.Where(p => p.Cost >= request.MinPrice);
if (request.MaxPrice > 0)
products = products.Where(p => p.Cost <= request.MaxPrice);
if (request.SortBy != QuerySortBy.None)
{
switch (request.SortBy)
{
case QuerySortBy.Cheapest:
products = products.OrderBy(p => p.Cost);
break;
case QuerySortBy.MostExpensive:
products = products.OrderByDescending(p => p.Cost);
break;
case QuerySortBy.MostPopular:
products = products.OrderByDescending(p => p.Rate);
break;
case QuerySortBy.MostViewed:
products = products.OrderByDescending(p => p.Viewed);
break;
}
}
return await products.Skip(request.Page * 10)
.Take(10)
.Select(ProductMapper.ProjectToSDto)
.ToListAsync(cancellationToken);

View File

@ -16,7 +16,16 @@ public class UpdateProductCommandHandler : IRequestHandler<UpdateProductCommand,
throw new AppException("Product not found", ApiResultStatusCode.NotFound);
var newEnt = Product.Create(request.PersianName, request.EnglishName, request.Summery, request.ExpertCheck,
request.Tags, request.Warranty,request.BeDisplayed,request.Cost,request.PackingCost, request.BrandId,request.CategoryId);
request.Tags,
request.Warranty,
request.BeDisplayed,
request.Cost,
request.PackingCost,
ent.ReviewCount,
ent.Rate,
ent.Viewed,
request.BrandId,
request.CategoryId);
newEnt.Id = ent.Id;
var dbSpecifications = await _repositoryWrapper.SetRepository<Specification>().TableNoTracking
@ -29,6 +38,7 @@ public class UpdateProductCommandHandler : IRequestHandler<UpdateProductCommand,
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
}
}
foreach (var specification in request.Specifications.Where(s => s.Id == default))
{
newEnt.AddSpecification(specification.Title, specification.Detail, specification.Value, specification.IsFeature, specification.ParentId);

View File

@ -0,0 +1,33 @@
using AppException = NetinaShop.Common.Models.Exception.AppException;
namespace NetinaShop.Repository.Handlers.Reviews;
public class CreateReviewCommandHandler : IRequestHandler<CreateReviewCommand,ReviewSDto>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public CreateReviewCommandHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<ReviewSDto> Handle(CreateReviewCommand request, CancellationToken cancellationToken)
{
var review = Review.Create(request.Title, request.Comment, request.Rate, request.IsBuyer, request.ProductId,
request.UserId);
var product = await _repositoryWrapper.SetRepository<Product>()
.TableNoTracking
.FirstOrDefaultAsync(p => p.Id == request.ProductId, cancellationToken);
if (product == null)
throw new AppException("Product not found",ApiResultStatusCode.NotFound);
product.AddRate(request.Rate);
_repositoryWrapper.SetRepository<Product>().Update(product);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
_repositoryWrapper.SetRepository<Review>().Add(review);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return review.AdaptToSDto();
}
}

View File

@ -0,0 +1,22 @@
namespace NetinaShop.Repository.Handlers.Reviews;
public class DeleteReviewCommandHandler : IRequestHandler<DeleteReviewCommand,bool>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public DeleteReviewCommandHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<bool> Handle(DeleteReviewCommand request, CancellationToken cancellationToken)
{
var review = await _repositoryWrapper.SetRepository<Review>().TableNoTracking
.FirstOrDefaultAsync(r => r.Id == request.Id, cancellationToken);
if (review == null)
throw new AppException("Review not found", ApiResultStatusCode.NotFound);
_repositoryWrapper.SetRepository<Review>().Delete(review);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return true;
}
}

View File

@ -0,0 +1,23 @@
namespace NetinaShop.Repository.Handlers.Reviews;
public class GetReviewQueryHandler : IRequestHandler<GetReviewQuery,ReviewLDto>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public GetReviewQueryHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<ReviewLDto> Handle(GetReviewQuery request, CancellationToken cancellationToken)
{
var review = await _repositoryWrapper.SetRepository<Review>()
.TableNoTracking
.Where(r => r.Id == request.Id)
.Select(ReviewMapper.ProjectToLDto)
.FirstOrDefaultAsync(cancellationToken);
if (review == null)
throw new AppException("Review not found", ApiResultStatusCode.NotFound);
return review;
}
}

View File

@ -0,0 +1,21 @@
namespace NetinaShop.Repository.Handlers.Reviews;
public class GetReviewsQueryHandler : IRequestHandler<GetReviewsQuery,List<ReviewSDto>>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public GetReviewsQueryHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<List<ReviewSDto>> Handle(GetReviewsQuery request, CancellationToken cancellationToken)
{
return await _repositoryWrapper.SetRepository<Review>()
.TableNoTracking
.OrderByDescending(r => r.CreatedAt)
.Skip(request.Page * 15)
.Take(15)
.Select(ReviewMapper.ProjectToSDto)
.ToListAsync(cancellationToken);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff