parent
2e8501190e
commit
fda7088abb
|
@ -38,12 +38,19 @@ public class ProductController : ICarterModule
|
|||
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ManageProducts))
|
||||
.HasApiVersion(1.0);
|
||||
|
||||
group.MapGet("{productId}/review",GetProductReviewsAsync)
|
||||
.WithDisplayName("Get Product Reviews")
|
||||
.HasApiVersion(1.0);
|
||||
|
||||
group.MapDelete("{id}", Delete)
|
||||
.WithDisplayName("Delete Product")
|
||||
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ManageProducts))
|
||||
.HasApiVersion(1.0);
|
||||
}
|
||||
|
||||
private async Task<IResult> GetProductReviewsAsync([FromQuery] int page, [FromRoute] Guid productId, IMediator mediator, CancellationToken cancellationToken)
|
||||
=> TypedResults.Ok(await mediator.Send(new GetReviewsQuery(page, productId), cancellationToken));
|
||||
|
||||
// GET:Get All Entity
|
||||
public async Task<IResult> GetAllAsync([FromQuery] int page,
|
||||
[FromQuery] string? productName,
|
||||
|
|
|
@ -13,13 +13,13 @@ public class ProductReviewController : ICarterModule
|
|||
.HasApiVersion(1.0);
|
||||
|
||||
group.MapGet("", GetAllAsync)
|
||||
.WithDisplayName("Get ProductReview")
|
||||
.WithDisplayName("Get Product Reviews")
|
||||
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ViewAllReviews, ApplicationPermission.ManageReview))
|
||||
.HasApiVersion(1.0);
|
||||
|
||||
group.MapPost("", PostAsync)
|
||||
.WithDisplayName("Create Product Review")
|
||||
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ManageReview, ApplicationPermission.AddReview))
|
||||
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser())
|
||||
.HasApiVersion(1.0);
|
||||
|
||||
group.MapPut("confirm/{id}", ConfirmAsync)
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<AssemblyVersion>1.2.11.13</AssemblyVersion>
|
||||
<FileVersion>1.2.11.13</FileVersion>
|
||||
<AssemblyVersion>1.3.12.16</AssemblyVersion>
|
||||
<FileVersion>1.3.12.16</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -7,6 +7,7 @@ builder.Host.UseSerilog();
|
|||
LoggerConfig.ConfigureSerilog();
|
||||
string env = builder.Environment.IsDevelopment() == true ? "Development" : "Production";
|
||||
builder.Host.UseContentRoot(Directory.GetCurrentDirectory());
|
||||
|
||||
if (builder.Environment.IsDevelopment())
|
||||
{
|
||||
string projectName = "Vesmeh";
|
||||
|
|
|
@ -104,7 +104,10 @@ public class PageService(
|
|||
{
|
||||
var newLink = pageSetting.RedirectItems.FirstOrDefault(f => f.OldUrl.ToLower().Trim() == oldEncode.ToLower().Trim());
|
||||
if (newLink != null)
|
||||
return newLink.NewUrl;
|
||||
{
|
||||
var response = newLink.NewUrl[0] == '/' ? newLink.NewUrl : $"/{newLink.NewUrl}";
|
||||
return response;
|
||||
}
|
||||
else
|
||||
throw new BaseApiException(ApiResultStatusCode.NotFound, "Url not found");
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
namespace Netina.Core.EntityServices.ReviewHandlers;
|
||||
using Review = Netina.Domain.Entities.Reviews.Review;
|
||||
|
||||
namespace Netina.Core.EntityServices.ReviewHandlers;
|
||||
|
||||
public class ConfirmReviewCommandHandler(IRepositoryWrapper repositoryWrapper)
|
||||
: IRequestHandler<ConfirmReviewCommand, bool>
|
||||
: IRequestHandler<ConfirmReviewCommand, Guid>
|
||||
{
|
||||
public async Task<bool> Handle(ConfirmReviewCommand request, CancellationToken cancellationToken)
|
||||
public async Task<Guid> Handle(ConfirmReviewCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var review = await repositoryWrapper.SetRepository<Review>().TableNoTracking
|
||||
.FirstOrDefaultAsync(r => r.Id == request.Id, cancellationToken);
|
||||
|
@ -13,6 +15,6 @@ public class ConfirmReviewCommandHandler(IRepositoryWrapper repositoryWrapper)
|
|||
|
||||
repositoryWrapper.SetRepository<Review>().Update(review);
|
||||
await repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
return true;
|
||||
return review.Id;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace Netina.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>;
|
||||
public sealed record CreateReviewCommand(string Title, string Comment, float Rate, bool IsBuyer, Guid ProductId, Guid UserId) : IRequest<Guid>;
|
||||
public sealed record UpdateReviewCommand(Guid Id,string Title, string Comment, float Rate, bool IsBuyer, Guid ProductId, Guid UserId): IRequest<Guid>;
|
||||
public sealed record ConfirmReviewCommand(Guid Id) : IRequest<Guid>;
|
||||
public sealed record DeleteReviewCommand(Guid Id) : IRequest<Guid>;
|
|
@ -1,4 +1,4 @@
|
|||
namespace Netina.Domain.CommandQueries.Queries;
|
||||
|
||||
public record GetReviewsQuery(int Page = 0) : IRequest<List<ReviewSDto>>;
|
||||
public record GetReviewsQuery(int Page = 0,Guid? ProductId = null) : IRequest<List<ReviewSDto>>;
|
||||
public record GetReviewQuery(Guid Id) : IRequest<ReviewLDto>;
|
|
@ -1,4 +1,6 @@
|
|||
namespace Netina.Domain.Dtos.LargDtos;
|
||||
using Review = Netina.Domain.Entities.Reviews.Review;
|
||||
|
||||
namespace Netina.Domain.Dtos.LargDtos;
|
||||
|
||||
public class ReviewLDto : BaseDto<ReviewLDto,Review>
|
||||
{
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
namespace Netina.Domain.Dtos.SmallDtos;
|
||||
using Review = Netina.Domain.Entities.Reviews.Review;
|
||||
|
||||
namespace Netina.Domain.Dtos.SmallDtos;
|
||||
|
||||
public class ReviewSDto : BaseDto<ReviewSDto, Review>
|
||||
{
|
||||
|
|
|
@ -69,16 +69,7 @@ public partial class ProductStorageFile
|
|||
}
|
||||
}
|
||||
|
||||
public partial class Review
|
||||
{
|
||||
public static Review Create(string title, string comment, float rate, bool isBuyer, Guid productId, Guid userId)
|
||||
{
|
||||
return new Review(title, comment, rate, isBuyer, productId, userId);
|
||||
}
|
||||
|
||||
public void ConfirmReview()
|
||||
=> IsConfirmed = true;
|
||||
}
|
||||
|
||||
public partial class Specification
|
||||
{
|
||||
|
|
|
@ -76,7 +76,7 @@ public partial class Product : ApiEntity
|
|||
public ProductCategory? Category { get; internal set; }
|
||||
|
||||
public List<Specification> Specifications { get; internal set; } = new();
|
||||
public List<Review> Reviews { get; internal set; } = new();
|
||||
public List<Reviews.Review> Reviews { get; internal set; } = new();
|
||||
public List<ProductStorageFile> Files { get; internal set; } = new();
|
||||
|
||||
public List<OrderProduct> OrderProducts { get; internal set; } = new();
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
namespace Netina.Domain.Entities.Reviews;
|
||||
|
||||
public partial class Review
|
||||
{
|
||||
public static Reviews.Review Create(string title, string comment, float rate, bool isBuyer, Guid productId, Guid userId)
|
||||
{
|
||||
return new Reviews.Review(title, comment, rate, isBuyer, productId, userId);
|
||||
}
|
||||
|
||||
public void ConfirmReview()
|
||||
=> IsConfirmed = true;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
namespace Netina.Domain.Entities.Products;
|
||||
namespace Netina.Domain.Entities.Reviews;
|
||||
[AdaptTwoWays("[name]LDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Map | MapType.MapToTarget | MapType.Projection)]
|
||||
[AdaptTwoWays("[name]SDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Map | MapType.MapToTarget)]
|
||||
[AdaptTo("[name]SDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Projection)]
|
|
@ -9,6 +9,7 @@ using Netina.Domain.Dtos.SmallDtos;
|
|||
using Netina.Domain.Entities.Brands;
|
||||
using Netina.Domain.Entities.ProductCategories;
|
||||
using Netina.Domain.Entities.Products;
|
||||
using Review = Netina.Domain.Entities.Reviews.Review;
|
||||
|
||||
namespace Netina.Domain.Mappers
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Linq.Expressions;
|
|||
using Netina.Domain.Dtos.LargDtos;
|
||||
using Netina.Domain.Dtos.SmallDtos;
|
||||
using Netina.Domain.Entities.Products;
|
||||
using Review = Netina.Domain.Entities.Reviews.Review;
|
||||
|
||||
namespace Netina.Domain.Mappers
|
||||
{
|
||||
|
|
|
@ -2,13 +2,19 @@
|
|||
|
||||
namespace Netina.Repository.Handlers.Reviews;
|
||||
|
||||
public class CreateReviewCommandHandler(IRepositoryWrapper repositoryWrapper)
|
||||
: IRequestHandler<CreateReviewCommand, ReviewSDto>
|
||||
public class CreateReviewCommandHandler(IRepositoryWrapper repositoryWrapper,ICurrentUserService currentUserService)
|
||||
: IRequestHandler<CreateReviewCommand, Guid>
|
||||
{
|
||||
public async Task<ReviewSDto> Handle(CreateReviewCommand request, CancellationToken cancellationToken)
|
||||
public async Task<Guid> Handle(CreateReviewCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
Guid userId = request.UserId;
|
||||
if (userId == default)
|
||||
{
|
||||
if (!Guid.TryParse(currentUserService.UserId, out userId))
|
||||
throw new AppException("User id is wrong", ApiResultStatusCode.BadRequest);
|
||||
}
|
||||
var review = Review.Create(request.Title, request.Comment, request.Rate, request.IsBuyer, request.ProductId,
|
||||
request.UserId);
|
||||
userId);
|
||||
var product = await repositoryWrapper.SetRepository<Product>()
|
||||
.TableNoTracking
|
||||
.FirstOrDefaultAsync(p => p.Id == request.ProductId, cancellationToken);
|
||||
|
@ -23,6 +29,6 @@ public class CreateReviewCommandHandler(IRepositoryWrapper repositoryWrapper)
|
|||
repositoryWrapper.SetRepository<Review>().Add(review);
|
||||
await repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return review.AdaptToSDto();
|
||||
return review.Id;
|
||||
}
|
||||
}
|
|
@ -1,17 +1,26 @@
|
|||
namespace Netina.Repository.Handlers.Reviews;
|
||||
|
||||
public class DeleteReviewCommandHandler(IRepositoryWrapper repositoryWrapper)
|
||||
: IRequestHandler<DeleteReviewCommand, bool>
|
||||
: IRequestHandler<DeleteReviewCommand, Guid>
|
||||
{
|
||||
public async Task<bool> Handle(DeleteReviewCommand request, CancellationToken cancellationToken)
|
||||
public async Task<Guid> 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);
|
||||
|
||||
var product = await repositoryWrapper.SetRepository<Product>()
|
||||
.TableNoTracking
|
||||
.FirstOrDefaultAsync(p => p.Id == review.ProductId, cancellationToken);
|
||||
if (product != null)
|
||||
{
|
||||
product.RemoveRate(review.Rate);
|
||||
repositoryWrapper.SetRepository<Product>().Update(product);
|
||||
await repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
repositoryWrapper.SetRepository<Review>().Delete(review);
|
||||
await repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
return true;
|
||||
return review.Id;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
namespace Netina.Repository.Handlers.Reviews;
|
||||
using Review = Netina.Domain.Entities.Reviews.Review;
|
||||
|
||||
namespace Netina.Repository.Handlers.Reviews;
|
||||
|
||||
public class GetReviewQueryHandler(IRepositoryWrapper repositoryWrapper) : IRequestHandler<GetReviewQuery, ReviewLDto>
|
||||
{
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
namespace Netina.Repository.Handlers.Reviews;
|
||||
using Review = Netina.Domain.Entities.Reviews.Review;
|
||||
|
||||
namespace Netina.Repository.Handlers.Reviews;
|
||||
|
||||
public class GetReviewsQueryHandler(IRepositoryWrapper repositoryWrapper)
|
||||
: IRequestHandler<GetReviewsQuery, List<ReviewSDto>>
|
||||
{
|
||||
public async Task<List<ReviewSDto>> Handle(GetReviewsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
return await repositoryWrapper.SetRepository<Review>()
|
||||
.TableNoTracking
|
||||
var query = repositoryWrapper.SetRepository<Review>()
|
||||
.TableNoTracking;
|
||||
if (request.ProductId != null)
|
||||
query = query.Where(q => q.ProductId == request.ProductId);
|
||||
|
||||
return await query
|
||||
.OrderByDescending(r => r.CreatedAt)
|
||||
.Skip(request.Page * 15)
|
||||
.Take(15)
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
<Using Include="Netina.Domain.Entities.Discounts" />
|
||||
<Using Include="Netina.Domain.Entities.ProductCategories" />
|
||||
<Using Include="Netina.Domain.Entities.Products" />
|
||||
<Using Include="Netina.Domain.Entities.Reviews" />
|
||||
<Using Include="Netina.Domain.Entities.Users" />
|
||||
<Using Include="Netina.Domain.Enums" />
|
||||
<Using Include="Netina.Domain.Extensions" />
|
||||
|
|
Loading…
Reference in New Issue