feat(FaqInActions) , feat(FaqManagementPage) , feat(FaqController)

subProduct
Amir Hossein Khademi 2024-08-07 16:15:53 +03:30
parent 5524cb4e43
commit 19f1f29548
45 changed files with 588 additions and 264 deletions

View File

@ -0,0 +1,56 @@
namespace Netina.Api.Controllers;
public class FaqController : ICarterModule
{
public void AddRoutes(IEndpointRouteBuilder app)
{
var group = app.NewVersionedApi("Faq")
.MapGroup("api/faq");
group.MapGet("/slug", GetFaqBySlugAsync)
.WithDisplayName("GetFaqBySlug")
.WithDescription("Get faq by slug , you have to send page slug")
.HasApiVersion(1.0);
group.MapGet("", GetFaqsAsync)
.WithDisplayName("GetFaqs")
.WithDescription("Get All Faqs ")
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer")
.RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ManageFaq))
.HasApiVersion(1.0);
group.MapPost("", CreateFaqAsync)
.WithDisplayName("Create Faq")
.WithDescription("Create Faq , you can create new faq or create update your faq ")
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer")
.RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ManageFaq))
.HasApiVersion(1.0);
group.MapPut("", UpdateFaqAsync)
.WithDisplayName("Update FaqAsync")
.WithDescription("Update Faq , you can create new faq or create update your faq ")
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer")
.RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ManageFaq))
.HasApiVersion(1.0);
group.MapDelete("{id}", DeleteFaqAsync)
.WithDisplayName("DeleteFaq")
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ManageFaq))
.HasApiVersion(1.0);
}
private async Task<IResult> DeleteFaqAsync([FromRoute]Guid id,[FromServices] IMediator mediator, CancellationToken cancellationToken)
=> TypedResults.Ok(await mediator.Send(new DeleteFaqCommand(Id:id), cancellationToken));
private async Task<IResult> GetFaqsAsync([FromQuery]int page, [FromQuery] int? count ,[FromServices] IMediator mediator, CancellationToken cancellationToken)
=> TypedResults.Ok(await mediator.Send(new GetFaqsQuery(Count: count ?? 0 , Page:page), cancellationToken));
private async Task<IResult> CreateFaqAsync([FromBody] CreateFaqCommand request,[FromServices]IMediator mediator , CancellationToken cancellationToken)
=> TypedResults.Ok(await mediator.Send(request, cancellationToken));
private async Task<IResult> UpdateFaqAsync([FromBody] UpdateFaqCommand request, [FromServices] IMediator mediator, CancellationToken cancellationToken)
=> TypedResults.Ok(await mediator.Send(request, cancellationToken));
private async Task<IResult> GetFaqBySlugAsync([FromQuery] string slug, [FromServices] IMediator mediator, CancellationToken cancellationToken)
=> TypedResults.Ok(await mediator.Send(new GetFaqQuery(null, slug), cancellationToken));
}

View File

@ -78,13 +78,14 @@ public class SeedController : ICarterModule
var baseCat = await mediator.Send(new CreateProductCategoryCommand("دسته بندی نشده", "محصولات دسته بندی نشده",
true,
default,
new List<StorageFileSDto>()),cancellationToken);
new List<StorageFileSDto>(),
new Dictionary<string, string>(),
new Dictionary<string, string>()),cancellationToken);
categories.Add(0,baseCat);
foreach (var requestDto in request)
{
var lDto = await mediator.Send(new CreateProductCategoryCommand(requestDto.Name,requestDto.Description,true,default,
new List<StorageFileSDto>()), cancellationToken);
new List<StorageFileSDto>(),new Dictionary<string, string>(),new Dictionary<string, string>()), cancellationToken);
categories.Add(requestDto.BaseCategoryId,lDto);
}
@ -97,13 +98,18 @@ public class SeedController : ICarterModule
if (key != "kKAYskyG8xPxKnJrHkuYxub4Ao2bnz7AOmNtwDT0RaqzaG7ZvbvaP29tCrC8wJ823RczJFXOIQT2bDOec4F38A==")
throw new AppException("Key is not valid", ApiResultStatusCode.UnAuthorized);
Dictionary<int, Guid> brands = new Dictionary<int, Guid>();
var baseBrand = await mediator.Send(new CreateBrandCommand("بدون برند","NoBrand", "محصولات بدون برند", false,string.Empty,
new List<StorageFileSDto>()), cancellationToken);
var baseBrand = await mediator.Send(new CreateBrandCommand("بدون برند","NoBrand",
"محصولات بدون برند",
false,
string.Empty,
new List<StorageFileSDto>(),
new Dictionary<string, string>(),
new Dictionary<string, string>()), cancellationToken);
brands.Add(0, baseBrand);
foreach (var requestDto in request)
{
var sDto = await mediator.Send(new CreateBrandCommand(requestDto.Name,string.Empty, requestDto.Description, false,
string.Empty, new List<StorageFileSDto>()), cancellationToken);
string.Empty, new List<StorageFileSDto>(),new Dictionary<string, string>(),new Dictionary<string, string>()), cancellationToken);
brands.Add(requestDto.BaseBrandId,sDto);
}

View File

@ -39,7 +39,9 @@ public class ExceptionHandlerMiddleware
catch (BaseApiException exception)
{
_logger.LogError(exception, exception.Message);
httpStatusCode = exception.HttpStatusCode;
httpStatusCode = exception.ApiStatusCode == ApiResultStatusCode.NotFound ? HttpStatusCode.NotFound :
exception.ApiStatusCode == ApiResultStatusCode.BadRequest ?
HttpStatusCode.BadRequest : exception.HttpStatusCode;
apiStatusCode = exception.ApiStatusCode;
if (_env.IsDevelopment())

View File

@ -1,8 +1,23 @@
namespace Netina.Domain.CommandQueries.Commands;
public sealed record CreateBrandCommand(string PersianName,string EnglishName, string Description , bool HasSpecialPage , string PageUrl, List<StorageFileSDto> Files) : IRequest<Guid>;
public sealed record CreateBrandCommand(string PersianName,
string EnglishName,
string Description ,
bool HasSpecialPage ,
string PageUrl,
List<StorageFileSDto> Files,
Dictionary<string, string> Faqs,
Dictionary<string, string> MetaTags) : IRequest<Guid>;
public sealed record UpdateBrandCommand(Guid Id,string PersianName, string EnglishName, string Description, bool HasSpecialPage, string PageUrl, List<StorageFileSDto> Files) : IRequest<bool>;
public sealed record UpdateBrandCommand(Guid Id,
string PersianName,
string EnglishName,
string Description,
bool HasSpecialPage,
string PageUrl,
List<StorageFileSDto> Files,
Dictionary<string, string> Faqs,
Dictionary<string, string> MetaTags) : IRequest<bool>;
public sealed record DeleteBrandCommand(Guid Id) : IRequest<bool>;

View File

@ -0,0 +1,15 @@
namespace Netina.Domain.CommandQueries.Commands;
public record CreateFaqCommand(
Dictionary<string, string> Faqs,
string Slug,
string Title) : IRequest<bool>;
public record DeleteFaqCommand(Guid Id) : IRequest<bool>;
public record UpdateFaqCommand(
Guid Id,
Dictionary<string, string> Faqs,
string Slug,
string Title) : IRequest<bool>;

View File

@ -5,7 +5,9 @@ public sealed record CreateProductCategoryCommand(
string Description,
bool IsMain,
Guid ParentId,
List<StorageFileSDto> Files) : IRequest<Guid>;
List<StorageFileSDto> Files,
Dictionary<string, string> Faqs,
Dictionary<string, string> MetaTags) : IRequest<Guid>;
public sealed record UpdateProductCategoryCommand(
Guid Id,
@ -13,6 +15,8 @@ public sealed record UpdateProductCategoryCommand(
string Description,
bool IsMain,
Guid ParentId,
List<StorageFileSDto> Files) : IRequest<bool>;
List<StorageFileSDto> Files,
Dictionary<string, string> Faqs,
Dictionary<string, string> MetaTags) : IRequest<bool>;
public sealed record DeleteProductCategoryCommand(Guid Id) : IRequest<bool>;

View File

@ -18,7 +18,9 @@ Guid BrandId,
Guid CategoryId,
DiscountSDto SpecialOffer,
List<SpecificationSDto> Specifications,
List<StorageFileSDto> Files):IRequest<ProductLDto>;
List<StorageFileSDto> Files,
Dictionary<string, string> Faqs,
Dictionary<string, string> MetaTags) : IRequest<ProductLDto>;
public sealed record UpdateProductCommand(
Guid Id,
@ -39,9 +41,12 @@ public sealed record UpdateProductCommand(
Guid CategoryId,
DiscountSDto SpecialOffer,
List<SpecificationSDto> Specifications,
List<StorageFileSDto> Files) : IRequest<bool>;
List<StorageFileSDto> Files,
Dictionary<string, string> Faqs,
Dictionary<string, string> MetaTags) : IRequest<bool>;
public sealed record ChangeProductDisplayedCommand(Guid Id, bool BeDisplayed) : IRequest<bool>;
public sealed record ChangeProductCostCommand(Guid Id, double Cost) : IRequest<bool>;
public sealed record DeleteProductCommand(Guid Id) : IRequest<bool>;

View File

@ -0,0 +1,4 @@
namespace Netina.Domain.CommandQueries.Queries;
public record GetFaqQuery(Guid? Id,string? Slug) : IRequest<BaseFaq>;
public record GetFaqsQuery(int Page , int Count = 0) : IRequest<List<BaseFaq>>;

View File

@ -6,6 +6,7 @@ public class BrandLDto : BaseDto<BrandLDto,Brand>
public string EnglishName { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public bool HasSpecialPage { get; set; }
public string Slug { get; set; } = string.Empty;
public string PageUrl { get; set; } = string.Empty;
public string HeaderFileName { get; set; } = string.Empty;
public List<StorageFileSDto> Files { get; internal set; } = new();

View File

@ -6,6 +6,7 @@ public class ProductCategoryLDto : BaseDto<ProductCategoryLDto, ProductCategory>
public string Description { get; set; } = string.Empty;
public Guid ParentId { get; set; }
public string ParentName { get; set; } = string.Empty;
public string Slug { get; set; } = string.Empty;
public bool IsMain { get; set; }
public List<ProductCategorySDto> Children { get; set; } = new();
public List<StorageFileSDto> Files { get; internal set; } = new();

View File

@ -5,6 +5,7 @@ public class BrandSDto : BaseDto<BrandSDto , Brand>
public string PersianName { get; set; } = string.Empty;
public string EnglishName { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string Slug { get; set; } = string.Empty;
public bool HasSpecialPage { get; set; }
public string PageUrl { get; set; } = string.Empty;
public string HeaderFileName { get; set; } = string.Empty;

View File

@ -1,10 +1,13 @@
namespace Netina.Domain.Entities.Brands;
using Microsoft.EntityFrameworkCore;
namespace Netina.Domain.Entities.Brands;
[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)]
[GenerateMapper]
[Index(nameof(Slug), IsUnique = true)]
public partial class Brand : ApiEntity
{
public Brand()

View File

@ -6,6 +6,9 @@
[AdaptTo("TorobProductResponseDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Projection)]
//[AdaptTo("[name]SDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Projection)]
[GenerateMapper]
[Index(nameof(Slug), IsUnique = true)]
public partial class Product : ApiEntity
{
public Product()

View File

@ -0,0 +1,13 @@
namespace Netina.Domain.Extensions;
public static class BrandExtension
{
public static string GetWebSiteUrl(this Brand product)
=> $"/brands/{product.Id}/{product.Slug}";
public static string GetWebSiteUrl(this BrandSDto product)
=> $"/brands/{product.Id}/{product.Slug}";
public static string GetWebSiteUrl(this BrandLDto product)
=> $"/brands/{product.Id}/{product.Slug}";
}

View File

@ -0,0 +1,13 @@
namespace Netina.Domain.Extensions;
public static class ProductCategoryExtension
{
public static string GetWebSiteUrl(this ProductCategory product)
=> $"/categories/{product.Id}/{product.Slug}";
public static string GetWebSiteUrl(this ProductCategorySDto product)
=> $"/categories/{product.Id}/{product.Slug}";
public static string GetWebSiteUrl(this ProductCategoryLDto product)
=> $"/categories/{product.Id}/{product.Slug}";
}

View File

@ -0,0 +1,13 @@
namespace Netina.Domain.Extensions;
public static class ProductExtension
{
public static string GetWebSiteUrl(this Product product)
=> $"/products/{product.Id}/{product.Slug}";
public static string GetWebSiteUrl(this ProductSDto product)
=> $"/products/{product.Id}/{product.Slug}";
public static string GetWebSiteUrl(this ProductLDto product)
=> $"/products/{product.Id}/{product.Slug}";
}

View File

@ -0,0 +1,8 @@
namespace Netina.Domain.MartenEntities.Faqs;
public class BaseFaq : MartenEntity
{
public Dictionary<string, string> Faqs { get; set; } = new();
public string Slug { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
}

View File

@ -1,7 +0,0 @@
namespace Netina.Domain.MartenEntities.Pages;
[PageClassDisplay("FAQPage", "صفحه سوالات متداول")]
public class FAQPage
{
public Dictionary<string, string> Faqs { get; set; } = new Dictionary<string, string>();
}

View File

@ -11,6 +11,13 @@ public static class ApplicationClaims
Value = ApplicationPermission.ManageDashboard,
};
public static ClaimDto ManageFaq { get; } = new ClaimDto
{
Title = "مدیریت سوالات متداول",
Type = CustomClaimType.Permission,
Value = ApplicationPermission.ManageFaq,
};
public static ClaimDto ManageBlogs { get; } = new ClaimDto
{
Title = "مدیریت بلاگ ها",
@ -278,7 +285,8 @@ public static class ApplicationClaims
ManageUsers,
ViewUsers,
ManageFiles,
ViewFiles
ViewFiles,
ManageFaq
};
public static List<Claim> AllClaims = new List<Claim>
@ -319,7 +327,8 @@ public static class ApplicationClaims
ManageUsers.GetClaim,
ViewUsers.GetClaim,
ManageFiles.GetClaim,
ViewFiles.GetClaim
ViewFiles.GetClaim,
ManageFaq.GetClaim
};
public static List<Claim> CustomerClaims = new List<Claim>

View File

@ -2,6 +2,8 @@
public static class ApplicationPermission
{
public static string ManageFaq = nameof(ManageFaq);
public const string ViewSettings = nameof(ViewSettings);
public const string ManageSettings = nameof(ManageSettings);

View File

@ -12,6 +12,7 @@
<PackageReference Include="Mapster" Version="7.4.0" />
<PackageReference Include="Mapster.Core" Version="1.2.1" />
<PackageReference Include="MediatR" Version="12.4.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.7" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="8.0.7" />
<PackageReference Include="PropertyChanged.Fody" Version="4.1.0" />
</ItemGroup>
@ -59,6 +60,7 @@
<ItemGroup>
<Using Include="Mapster" />
<Using Include="MediatR" />
<Using Include="Microsoft.EntityFrameworkCore"/>
<Using Include="Microsoft.AspNetCore.Identity" />
<Using Include="Microsoft.Extensions.Logging" />
<Using Include="Netina.Common.Extensions" />
@ -78,6 +80,7 @@
<Using Include="Netina.Domain.Entities.Users" />
<Using Include="Netina.Domain.Entities.Warehouses" />
<Using Include="Netina.Domain.Enums" />
<Using Include="Netina.Domain.MartenEntities.Faqs" />
<Using Include="Netina.Domain.MartenEntities.Settings" />
<Using Include="System.ComponentModel.DataAnnotations" />
<Using Include="System.Diagnostics" />

View File

@ -1,33 +1,52 @@
using Marten;
using Netina.Repository.Abstracts;
namespace Netina.Infrastructure.Marten;
public class MartenRepository<TMartenEntity> : IMartenRepository<TMartenEntity> where TMartenEntity : IMartenEntity
public class MartenRepository<TMartenEntity>(IDocumentStore documentStore, ICurrentUserService currentUserService)
: IMartenRepository<TMartenEntity>
where TMartenEntity : IMartenEntity
{
private readonly IDocumentStore _documentStore;
public MartenRepository(IDocumentStore documentStore)
{
_documentStore = documentStore;
}
private readonly ICurrentUserService _currentUserService = currentUserService;
public async Task<List<TMartenEntity>> GetEntitiesAsync(CancellationToken cancellation)
{
await using var session = _documentStore.QuerySession();
var entities = await session.Query<TMartenEntity>().ToListAsync(cancellation);
await using var session = documentStore.QuerySession();
var entities = await session
.Query<TMartenEntity>()
.ToListAsync(cancellation);
return entities.ToList();
}
public async Task<List<TMartenEntity>> GetEntitiesAsync(int page, int count, CancellationToken cancellation)
{
await using var session = documentStore.QuerySession();
var entities = await session
.Query<TMartenEntity>()
.Skip(page * count)
.Take(count)
.ToListAsync(cancellation);
return entities.ToList();
}
public async Task<List<TMartenEntity>> GetEntitiesAsync(Expression<Func<TMartenEntity, bool>> expression, int page, int count, CancellationToken cancellation)
{
await using var session = documentStore.QuerySession();
var entities = await session.Query<TMartenEntity>().Where(expression)
.Skip(page * count)
.Take(count)
.ToListAsync(cancellation);
return entities.ToList();
}
public async Task<List<TMartenEntity>> GetEntitiesAsync(Expression<Func<TMartenEntity, bool>> expression, CancellationToken cancellation)
{
await using var session = _documentStore.QuerySession();
await using var session = documentStore.QuerySession();
var entities = await session.Query<TMartenEntity>().Where(expression).ToListAsync(cancellation);
return entities.ToList();
}
public async Task<TMartenEntity> GetEntityAsync(Guid id, CancellationToken cancellation)
{
await using var session = _documentStore.QuerySession();
await using var session = documentStore.QuerySession();
var setting = await session.LoadAsync<TMartenEntity>(id, cancellation);
if (setting == null)
throw new AppException($"{nameof(setting)} not found", ApiResultStatusCode.NotFound);
@ -36,7 +55,7 @@ public class MartenRepository<TMartenEntity> : IMartenRepository<TMartenEntity>
public async Task<TMartenEntity?> GetEntityAsync(Expression<Func<TMartenEntity, bool>> expression, CancellationToken cancellation)
{
await using var session = _documentStore.QuerySession();
await using var session = documentStore.QuerySession();
var entity = await session.Query<TMartenEntity>().FirstOrDefaultAsync(expression, cancellation);
return entity;
}
@ -46,16 +65,26 @@ public class MartenRepository<TMartenEntity> : IMartenRepository<TMartenEntity>
if (entity == null)
throw new AppException($"{nameof(entity)} is null", ApiResultStatusCode.BadRequest);
await using var session = _documentStore.LightweightSession();
await using var session = documentStore.LightweightSession();
session.Store(entity);
await session.SaveChangesAsync(cancellation);
}
public async Task UpdateEntityAsync(TMartenEntity entity, CancellationToken cancellation = default)
{
if (entity == null)
throw new AppException($"{nameof(entity)} is null", ApiResultStatusCode.BadRequest);
await using var session = documentStore.LightweightSession();
session.Update(entity);
await session.SaveChangesAsync(cancellation);
}
public async Task RemoveEntityAsync(TMartenEntity entity, CancellationToken cancellation)
{
if (entity == null)
throw new AppException($"{nameof(entity)} is null", ApiResultStatusCode.BadRequest);
await using var session = _documentStore.LightweightSession();
await using var session = documentStore.LightweightSession();
session.Delete(entity);
await session.SaveChangesAsync(cancellation);
}

View File

@ -1,16 +1,10 @@
using Marten;
using Netina.Repository.Abstracts;
namespace Netina.Infrastructure.Marten;
public class MartenRepositoryWrapper : IMartenRepositoryWrapper
public class MartenRepositoryWrapper(IDocumentStore documentStore,ICurrentUserService currentUserService) : IMartenRepositoryWrapper
{
private readonly IDocumentStore _documentStore;
public MartenRepositoryWrapper(IDocumentStore documentStore)
{
_documentStore = documentStore;
}
public IMartenRepository<TMartenEntity> SetRepository<TMartenEntity>() where TMartenEntity : IMartenEntity
=> new MartenRepository<TMartenEntity>(_documentStore);
=> new MartenRepository<TMartenEntity>(documentStore, currentUserService);
}

View File

@ -102,7 +102,7 @@ public class DigikalaScraper : IDigikalaScraper
newSummery,
string.Empty, string.Empty, string.Empty, true, 0,
0, 0, false
, 5, false, nonBrand.Id, nonCat.Id, new DiscountSDto(), specifications, files);
, 5, false, nonBrand.Id, nonCat.Id, new DiscountSDto(), specifications, files,new Dictionary<string, string>(),new Dictionary<string, string>());
await _mediator.Send(request, cancellationToken);
return true;

View File

@ -2,14 +2,8 @@
namespace Netina.Repository.Handlers.Brands;
public class CreateBrandCommandHandler : IRequestHandler<CreateBrandCommand , Guid>
public class CreateBrandCommandHandler(IRepositoryWrapper repositoryWrapper,IMartenRepositoryWrapper martenRepositoryWrapper , IMediator mediator) : IRequestHandler<CreateBrandCommand, Guid>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public CreateBrandCommandHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<Guid> Handle(CreateBrandCommand request, CancellationToken cancellationToken)
{
var ent = Brand.Create(request.PersianName,request.EnglishName, request.Description, request.HasSpecialPage, request.PageUrl);
@ -17,8 +11,28 @@ public class CreateBrandCommandHandler : IRequestHandler<CreateBrandCommand , Gu
{
ent.AddFile(file.Name, file.FileLocation, file.FileName, file.IsHeader, file.IsPrimary, file.FileType);
}
_repositoryWrapper.SetRepository<Brand>().Add(ent);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
repositoryWrapper.SetRepository<Brand>().Add(ent);
await repositoryWrapper.SaveChangesAsync(cancellationToken);
await UpdateFaqAsync(ent, request.Faqs, cancellationToken);
return ent.Id;
}
private async Task UpdateFaqAsync(Brand newEnt, Dictionary<string, string> faqs, CancellationToken cancellationToken)
{
var url = newEnt.GetWebSiteUrl();
var oldFaq = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(f => f.Slug == newEnt.Slug, cancellationToken);
var newFaq = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(f => f.Slug == url, cancellationToken);
if (oldFaq != null)
await mediator.Send(new DeleteFaqCommand(oldFaq.Id), cancellationToken);
if (newFaq == null)
await mediator.Send(new CreateFaqCommand(faqs, url, newEnt.EnglishName), cancellationToken);
else
await mediator.Send(new UpdateFaqCommand(newFaq.Id, faqs, url, newEnt.EnglishName), cancellationToken);
}
}

View File

@ -1,19 +1,12 @@
using Microsoft.EntityFrameworkCore;
using Netina.Domain.Entities.Brands;
using Netina.Domain.Entities.Brands;
namespace Netina.Repository.Handlers.Brands;
public class UpdateBrandCommandHandler : IRequestHandler<UpdateBrandCommand,bool>
public class UpdateBrandCommandHandler(IRepositoryWrapper repositoryWrapper,IMartenRepositoryWrapper martenRepositoryWrapper,IMediator mediator) : IRequestHandler<UpdateBrandCommand, bool>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public UpdateBrandCommandHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<bool> Handle(UpdateBrandCommand request, CancellationToken cancellationToken)
{
var ent = await _repositoryWrapper.SetRepository<Brand>().TableNoTracking
var ent = await repositoryWrapper.SetRepository<Brand>().TableNoTracking
.FirstOrDefaultAsync(b => b.Id == request.Id, cancellationToken);
if (ent == null)
throw new AppException("Brand not found");
@ -22,14 +15,14 @@ public class UpdateBrandCommandHandler : IRequestHandler<UpdateBrandCommand,bool
newEnt.CreatedAt = ent.CreatedAt;
newEnt.CreatedBy = ent.CreatedBy;
var dbFiles = await _repositoryWrapper.SetRepository<BrandStorageFile>().TableNoTracking
var dbFiles = await repositoryWrapper.SetRepository<BrandStorageFile>().TableNoTracking
.Where(s => s.BrandId == newEnt.Id).ToListAsync(cancellationToken);
foreach (var dbFile in dbFiles)
{
if (request.Files.FirstOrDefault(s => s.Id == dbFile.Id) == null)
{
_repositoryWrapper.SetRepository<BrandStorageFile>().Delete(dbFile);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
repositoryWrapper.SetRepository<BrandStorageFile>().Delete(dbFile);
await repositoryWrapper.SaveChangesAsync(cancellationToken);
}
}
foreach (var file in request.Files.Where(f => f.Id == default))
@ -37,8 +30,26 @@ public class UpdateBrandCommandHandler : IRequestHandler<UpdateBrandCommand,bool
newEnt.AddFile(file.Name, file.FileLocation, file.FileName, file.IsHeader, file.IsPrimary, file.FileType);
}
_repositoryWrapper.SetRepository<Brand>().Update(newEnt);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
repositoryWrapper.SetRepository<Brand>().Update(newEnt);
await repositoryWrapper.SaveChangesAsync(cancellationToken);
await UpdateFaqAsync(newEnt, request.Faqs, cancellationToken);
return true;
}
private async Task UpdateFaqAsync(Brand newEnt, Dictionary<string, string> faqs, CancellationToken cancellationToken)
{
var url = newEnt.GetWebSiteUrl();
var oldFaq = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(f => f.Slug == newEnt.Slug, cancellationToken);
var newFaq = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(f => f.Slug == url, cancellationToken);
if (oldFaq != null)
await mediator.Send(new DeleteFaqCommand(oldFaq.Id), cancellationToken);
if (newFaq == null)
await mediator.Send(new CreateFaqCommand(faqs, url, newEnt.EnglishName), cancellationToken);
else
await mediator.Send(new UpdateFaqCommand(newFaq.Id, faqs, url, newEnt.EnglishName), cancellationToken);
}
}

View File

@ -0,0 +1,18 @@
namespace Netina.Repository.Handlers.Faqs;
public class CreateFaqCommandHandler(IMartenRepositoryWrapper martenRepositoryWrapper)
: IRequestHandler<CreateFaqCommand, bool>
{
public async Task<bool> Handle(CreateFaqCommand request, CancellationToken cancellationToken)
{
var faq = new BaseFaq
{
Faqs = request.Faqs,
Slug = request.Slug,
Title = request.Title
};
await martenRepositoryWrapper.SetRepository<BaseFaq>()
.AddOrUpdateEntityAsync(faq, cancellationToken);
return true;
}
}

View File

@ -0,0 +1,12 @@
namespace Netina.Repository.Handlers.Faqs;
public class DeleteFaqCommandHandler(IMartenRepositoryWrapper martenRepositoryWrapper)
: IRequestHandler<DeleteFaqCommand, bool>
{
public async Task<bool> Handle(DeleteFaqCommand request, CancellationToken cancellationToken)
{
var ent = await martenRepositoryWrapper.SetRepository<BaseFaq>().GetEntityAsync(request.Id, cancellationToken);
await martenRepositoryWrapper.SetRepository<BaseFaq>().RemoveEntityAsync(ent, cancellationToken);
return true;
}
}

View File

@ -0,0 +1,27 @@
namespace Netina.Repository.Handlers.Faqs;
public class GetFaqQueryHandler(IMartenRepositoryWrapper martenRepositoryWrapper)
: IRequestHandler<GetFaqQuery, BaseFaq>
{
public async Task<BaseFaq> Handle(GetFaqQuery request, CancellationToken cancellationToken)
{
if (request.Id is not null)
{
var ent = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(request.Id.Value, cancellationToken);
if (ent == null)
return new BaseFaq();
return ent;
}else if (request.Slug != null)
{
var htmlSlug = request.Slug;
var ent = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(f=>f.Slug == htmlSlug, cancellationToken);
if (ent == null)
return new BaseFaq();
return ent;
}
return new BaseFaq();
}
}

View File

@ -0,0 +1,16 @@
namespace Netina.Repository.Handlers.Faqs;
public class GetFaqsQueryHandler(IMartenRepositoryWrapper martenRepositoryWrapper)
: IRequestHandler<GetFaqsQuery, List<BaseFaq>>
{
public async Task<List<BaseFaq>> Handle(GetFaqsQuery request, CancellationToken cancellationToken)
{
var count = request.Count > 0 ? request.Count : 20;
if (count > 50)
throw new BaseApiException(ApiResultStatusCode.BadRequest, "Count limit is 50");
var response = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntitiesAsync(request.Page, count, cancellationToken);
response.ForEach(f => { f.Faqs ??= new Dictionary<string, string>(); });
return response;
}
}

View File

@ -0,0 +1,24 @@
namespace Netina.Repository.Handlers.Faqs;
public class UpdateFaqCommandHandler(IMartenRepositoryWrapper martenRepositoryWrapper)
: IRequestHandler<UpdateFaqCommand, bool>
{
public async Task<bool> Handle(UpdateFaqCommand request, CancellationToken cancellationToken)
{
var ent = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(request.Id, cancellationToken);
if (ent == null)
throw new BaseApiException(ApiResultStatusCode.NotFound, "Faq not found");
var newEnt = new BaseFaq
{
Id = ent.Id,
Faqs = request.Faqs,
Slug = request.Slug,
Title = request.Title
};
await martenRepositoryWrapper.SetRepository<BaseFaq>()
.UpdateEntityAsync(newEnt, cancellationToken);
return true;
}
}

View File

@ -1,14 +1,8 @@
namespace Netina.Repository.Handlers.ProductCategories;
public class CreateProductCategoryCommandHandler : IRequestHandler<CreateProductCategoryCommand,Guid>
public class CreateProductCategoryCommandHandler(IRepositoryWrapper repositoryWrapper,IMediator mediator,IMartenRepositoryWrapper martenRepositoryWrapper)
: IRequestHandler<CreateProductCategoryCommand, Guid>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public CreateProductCategoryCommandHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<Guid> Handle(CreateProductCategoryCommand request, CancellationToken cancellationToken)
{
var ent = ProductCategory.Create(request.Name, request.Description, request.IsMain);
@ -18,8 +12,25 @@ public class CreateProductCategoryCommandHandler : IRequestHandler<CreateProduct
{
ent.AddFile(file.Name, file.FileLocation, file.FileName, file.IsHeader, file.IsPrimary, file.FileType);
}
_repositoryWrapper.SetRepository<ProductCategory>().Add(ent);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
repositoryWrapper.SetRepository<ProductCategory>().Add(ent);
await repositoryWrapper.SaveChangesAsync(cancellationToken);
await UpdateFaqAsync(ent, request.Faqs, cancellationToken);
return ent.Id;
}
private async Task UpdateFaqAsync(ProductCategory newEnt, Dictionary<string, string> faqs, CancellationToken cancellationToken)
{
var url = newEnt.GetWebSiteUrl();
var oldFaq = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(f => f.Slug == newEnt.Slug, cancellationToken);
var newFaq = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(f => f.Slug == url, cancellationToken);
if (oldFaq != null)
await mediator.Send(new DeleteFaqCommand(oldFaq.Id), cancellationToken);
if (newFaq == null)
await mediator.Send(new CreateFaqCommand(faqs, url, newEnt.Name), cancellationToken);
else
await mediator.Send(new UpdateFaqCommand(newFaq.Id, faqs, url, newEnt.Name), cancellationToken);
}
}

View File

@ -1,24 +1,17 @@
using Microsoft.EntityFrameworkCore;
namespace Netina.Repository.Handlers.ProductCategories;
namespace Netina.Repository.Handlers.ProductCategories;
public class DeleteProductCategoryCommandHandler : IRequestHandler<DeleteProductCategoryCommand, bool>
public class DeleteProductCategoryCommandHandler(IRepositoryWrapper repositoryWrapper)
: IRequestHandler<DeleteProductCategoryCommand, bool>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public DeleteProductCategoryCommandHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<bool> Handle(DeleteProductCategoryCommand request, CancellationToken cancellationToken)
{
var ent = await _repositoryWrapper.SetRepository<ProductCategory>().TableNoTracking
var ent = await repositoryWrapper.SetRepository<ProductCategory>().TableNoTracking
.FirstOrDefaultAsync(c => c.Id == request.Id, cancellationToken);
if (ent == null)
throw new AppException("ProductCategory not found", ApiResultStatusCode.NotFound);
_repositoryWrapper.SetRepository<ProductCategory>().Delete(ent);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
repositoryWrapper.SetRepository<ProductCategory>().Delete(ent);
await repositoryWrapper.SaveChangesAsync(cancellationToken);
return true;
}
}

View File

@ -2,21 +2,16 @@
namespace Netina.Repository.Handlers.ProductCategories;
public class GetProductCategoriesQueryHandler : IRequestHandler<GetProductCategoriesQuery, List<ProductCategorySDto>>
public class GetProductCategoriesQueryHandler(IRepositoryWrapper repositoryWrapper)
: IRequestHandler<GetProductCategoriesQuery, List<ProductCategorySDto>>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public GetProductCategoriesQueryHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<List<ProductCategorySDto>> Handle(GetProductCategoriesQuery request, CancellationToken cancellationToken)
{
IQueryable<ProductCategory> basCategories;
List<ProductCategorySDto> groupCats;
if (request.CategoryName != null)
{
basCategories = _repositoryWrapper.SetRepository<ProductCategory>()
basCategories = repositoryWrapper.SetRepository<ProductCategory>()
.TableNoTracking
.Where(c => c.Name.Trim().Contains(request.CategoryName.Trim()))
.OrderByDescending(c => c.CreatedAt);
@ -24,7 +19,7 @@ public class GetProductCategoriesQueryHandler : IRequestHandler<GetProductCatego
else
{
basCategories = _repositoryWrapper.SetRepository<ProductCategory>()
basCategories = repositoryWrapper.SetRepository<ProductCategory>()
.TableNoTracking
.OrderByDescending(c=>c.CreatedAt);
}

View File

@ -2,15 +2,9 @@
namespace Netina.Repository.Handlers.ProductCategories;
public class GetProductCategoryChildrenQueryHandler : IRequestHandler<GetProductCategoryChildrenQuery,List<Guid>>
public class GetProductCategoryChildrenQueryHandler(IRepositoryWrapper repositoryWrapper)
: IRequestHandler<GetProductCategoryChildrenQuery, List<Guid>>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public GetProductCategoryChildrenQueryHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<List<Guid>> Handle(GetProductCategoryChildrenQuery request, CancellationToken cancellationToken)
{
if (request.Id == default)
@ -23,7 +17,7 @@ public class GetProductCategoryChildrenQueryHandler : IRequestHandler<GetProduct
private async Task<List<Guid>> Recursive(Guid id,CancellationToken cancellationToken)
{
var children = await _repositoryWrapper.SetRepository<ProductCategory>()
var children = await repositoryWrapper.SetRepository<ProductCategory>()
.TableNoTracking
.Where(c => c.ParentId == id)
.Select(c => c.Id)

View File

@ -2,17 +2,12 @@
namespace Netina.Repository.Handlers.ProductCategories;
public class GetProductCategoryQueryHandler : IRequestHandler<GetProductCategoryQuery, ProductCategoryLDto>
public class GetProductCategoryQueryHandler(IRepositoryWrapper repositoryWrapper)
: IRequestHandler<GetProductCategoryQuery, ProductCategoryLDto>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public GetProductCategoryQueryHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<ProductCategoryLDto> Handle(GetProductCategoryQuery request, CancellationToken cancellationToken)
{
var ent = await _repositoryWrapper.SetRepository<ProductCategory>().TableNoTracking
var ent = await repositoryWrapper.SetRepository<ProductCategory>().TableNoTracking
.Where(b => b.Id == request.Id)
.Select(ProductCategoryMapper.ProjectToLDto)
.FirstOrDefaultAsync(cancellationToken);

View File

@ -1,18 +1,11 @@
using Microsoft.EntityFrameworkCore;
namespace Netina.Repository.Handlers.ProductCategories;
namespace Netina.Repository.Handlers.ProductCategories;
public class UpdateProductCategoryCommandHandler : IRequestHandler<UpdateProductCategoryCommand, bool>
public class UpdateProductCategoryCommandHandler(IRepositoryWrapper repositoryWrapper,IMediator mediator,IMartenRepositoryWrapper martenRepositoryWrapper)
: IRequestHandler<UpdateProductCategoryCommand, bool>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public UpdateProductCategoryCommandHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<bool> Handle(UpdateProductCategoryCommand request, CancellationToken cancellationToken)
{
var ent = await _repositoryWrapper.SetRepository<ProductCategory>().TableNoTracking
var ent = await repositoryWrapper.SetRepository<ProductCategory>().TableNoTracking
.FirstOrDefaultAsync(c => c.Id == request.Id, cancellationToken);
if (ent == null)
throw new AppException("ProductCategory not found", ApiResultStatusCode.NotFound);
@ -25,22 +18,39 @@ public class UpdateProductCategoryCommandHandler : IRequestHandler<UpdateProduct
newEnt.SetParent(request.ParentId);
var dbFiles = await _repositoryWrapper.SetRepository<ProductCategoryStorageFile>().TableNoTracking
var dbFiles = await repositoryWrapper.SetRepository<ProductCategoryStorageFile>().TableNoTracking
.Where(s => s.CategoryId == newEnt.Id).ToListAsync(cancellationToken);
foreach (var dbFile in dbFiles)
{
if (request.Files.FirstOrDefault(s => s.Id == dbFile.Id) == null)
{
_repositoryWrapper.SetRepository<ProductCategoryStorageFile>().Delete(dbFile);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
repositoryWrapper.SetRepository<ProductCategoryStorageFile>().Delete(dbFile);
await repositoryWrapper.SaveChangesAsync(cancellationToken);
}
}
foreach (var file in request.Files.Where(f => f.Id == default))
{
newEnt.AddFile(file.Name, file.FileLocation, file.FileName, file.IsHeader, file.IsPrimary, file.FileType);
}
_repositoryWrapper.SetRepository<ProductCategory>().Update(newEnt);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
repositoryWrapper.SetRepository<ProductCategory>().Update(newEnt);
await repositoryWrapper.SaveChangesAsync(cancellationToken);
await UpdateFaqAsync(newEnt, request.Faqs, cancellationToken);
return true;
}
private async Task UpdateFaqAsync(ProductCategory newEnt, Dictionary<string, string> faqs, CancellationToken cancellationToken)
{
var url = newEnt.GetWebSiteUrl();
var oldFaq = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(f => f.Slug == newEnt.Slug, cancellationToken);
var newFaq = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(f => f.Slug == url, cancellationToken);
if (oldFaq != null)
await mediator.Send(new DeleteFaqCommand(oldFaq.Id), cancellationToken);
if (newFaq == null)
await mediator.Send(new CreateFaqCommand(faqs, url, newEnt.Name), cancellationToken);
else
await mediator.Send(new UpdateFaqCommand(newFaq.Id, faqs, url, newEnt.Name), cancellationToken);
}
}

View File

@ -1,16 +1,8 @@
namespace Netina.Repository.Handlers.Products;
public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand, ProductLDto>
public class CreateProductCommandHandler(IRepositoryWrapper repositoryWrapper,IMartenRepositoryWrapper martenRepositoryWrapper, IMediator mediator)
: IRequestHandler<CreateProductCommand, ProductLDto>
{
private readonly IRepositoryWrapper _repositoryWrapper;
private readonly IMediator _mediator;
public CreateProductCommandHandler(IRepositoryWrapper repositoryWrapper,IMediator mediator)
{
_repositoryWrapper = repositoryWrapper;
_mediator = mediator;
}
public async Task<ProductLDto> Handle(CreateProductCommand request, CancellationToken cancellationToken)
{
@ -34,8 +26,8 @@ public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand,
_repositoryWrapper.SetRepository<Product>().Add(ent);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
repositoryWrapper.SetRepository<Product>().Add(ent);
await repositoryWrapper.SaveChangesAsync(cancellationToken);
if (request.IsSpecialOffer)
{
@ -48,15 +40,34 @@ public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand,
if (request.SpecialOffer.Id == default)
{
var discountRequest = discount.Adapt<CreateDiscountCommand>();
await _mediator.Send(discountRequest, cancellationToken);
await mediator.Send(discountRequest, cancellationToken);
}
else
{
var discountRequest = discount.Adapt<UpdateDiscountCommand>();
await _mediator.Send(discountRequest, cancellationToken);
await mediator.Send(discountRequest, cancellationToken);
}
}
await UpdateFaqAsync(ent, request.Faqs, cancellationToken);
return ent.AdaptToLDto();
}
private async Task UpdateFaqAsync(Product newEnt, Dictionary<string, string> faqs, CancellationToken cancellationToken)
{
var url = newEnt.GetWebSiteUrl();
var oldFaq = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(f => f.Slug == newEnt.Slug, cancellationToken);
var newFaq = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(f => f.Slug == url, cancellationToken);
if (oldFaq != null)
await mediator.Send(new DeleteFaqCommand(oldFaq.Id), cancellationToken);
if (newFaq == null)
await mediator.Send(new CreateFaqCommand(faqs, url, newEnt.EnglishName), cancellationToken);
else
await mediator.Send(new UpdateFaqCommand(newFaq.Id, faqs, url, newEnt.EnglishName), cancellationToken);
}
}

View File

@ -2,23 +2,18 @@
namespace Netina.Repository.Handlers.Products;
public class DeleteProductCommandHandler : IRequestHandler<DeleteProductCommand, bool>
public class DeleteProductCommandHandler(IRepositoryWrapper repositoryWrapper)
: IRequestHandler<DeleteProductCommand, bool>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public DeleteProductCommandHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<bool> Handle(DeleteProductCommand request, CancellationToken cancellationToken)
{
var ent = await _repositoryWrapper.SetRepository<Product>().TableNoTracking
var ent = await repositoryWrapper.SetRepository<Product>().TableNoTracking
.FirstOrDefaultAsync(d => d.Id == request.Id, cancellationToken);
if (ent == null)
throw new AppException("Product NotFound", ApiResultStatusCode.NotFound);
_repositoryWrapper.SetRepository<Product>().Delete(ent);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
repositoryWrapper.SetRepository<Product>().Delete(ent);
await repositoryWrapper.SaveChangesAsync(cancellationToken);
return true;
}
}

View File

@ -1,6 +1,4 @@
using Microsoft.EntityFrameworkCore;
namespace Netina.Repository.Handlers.Products;
namespace Netina.Repository.Handlers.Products;
public class GetProductQueryHandler(IRepositoryWrapper repositoryWrapper, IMediator mediator)
: IRequestHandler<GetProductQuery, GetProductResponseDto>
@ -13,7 +11,7 @@ public class GetProductQueryHandler(IRepositoryWrapper repositoryWrapper, IMedia
.FirstOrDefaultAsync(cancellationToken);
if (ent == null)
throw new AppException("Product not found", ApiResultStatusCode.NotFound);
throw new BaseApiException(ApiResultStatusCode.NotFound,"Product not found");
await mediator.Send(new CalculateProductDiscountCommand(ent), cancellationToken);

View File

@ -2,25 +2,19 @@
namespace Netina.Repository.Handlers.Products;
public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, GetProductsResponseDto>
public class GetProductsQueryHandler(
IRepositoryWrapper repositoryWrapper,
IMediator mediator,
ICurrentUserService currentUserService)
: IRequestHandler<GetProductsQuery, GetProductsResponseDto>
{
private readonly IRepositoryWrapper _repositoryWrapper;
private readonly IMediator _mediator;
private readonly ICurrentUserService _currentUserService;
public GetProductsQueryHandler(IRepositoryWrapper repositoryWrapper, IMediator mediator, ICurrentUserService currentUserService)
{
_repositoryWrapper = repositoryWrapper;
_mediator = mediator;
_currentUserService = currentUserService;
}
public async Task<GetProductsResponseDto> Handle(GetProductsQuery request, CancellationToken cancellationToken)
{
var response = new GetProductsResponseDto();
var products = _repositoryWrapper.SetRepository<Product>().TableNoTracking;
if (_currentUserService.JwtToken == null)
var products = repositoryWrapper.SetRepository<Product>().TableNoTracking;
if (currentUserService.JwtToken == null)
products = products.Where(p => p.BeDisplayed);
var roleClaim = _currentUserService.JwtToken?.Claims.FirstOrDefault(c => c.Type == "role");
var roleClaim = currentUserService.JwtToken?.Claims.FirstOrDefault(c => c.Type == "role");
if (roleClaim != null && roleClaim.Value.Contains("Customer"))
products = products.Where(p => p.BeDisplayed);
@ -46,7 +40,7 @@ public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, GetProd
if (request.CategoryId != default)
{
var cats = await _mediator.Send(new GetProductCategoryChildrenQuery(request.CategoryId), cancellationToken);
var cats = await mediator.Send(new GetProductCategoryChildrenQuery(request.CategoryId), cancellationToken);
products = products.Where(p => cats.Contains(p.CategoryId));
}
if (request.BrandIds is { Length: > 0 })
@ -61,7 +55,7 @@ public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, GetProd
{
if (request.SpecialOffer.Value)
{
var productDiscount = await _repositoryWrapper.SetRepository<ProductDiscount>()
var productDiscount = await repositoryWrapper.SetRepository<ProductDiscount>()
.TableNoTracking
.Where(d => d.HasCode == false && d.IsSpecialOffer && d.ExpireDate.Date >= DateTime.Today.Date)
.OrderByDescending(d => d.CreatedAt)
@ -92,7 +86,7 @@ public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, GetProd
foreach (var productSDto in productSDtos)
{
await _mediator.Send(new CalculateProductDiscountCommand(productSDto), cancellationToken);
await mediator.Send(new CalculateProductDiscountCommand(productSDto), cancellationToken);
}
response.Products = productSDtos;

View File

@ -1,8 +1,6 @@
using Microsoft.EntityFrameworkCore;
namespace Netina.Repository.Handlers.Products;
namespace Netina.Repository.Handlers.Products;
public class UpdateProductCommandHandler(IRepositoryWrapper repositoryWrapper, IMediator mediator)
public class UpdateProductCommandHandler(IRepositoryWrapper repositoryWrapper,IMartenRepositoryWrapper martenRepositoryWrapper, IMediator mediator)
: IRequestHandler<UpdateProductCommand, bool>
{
public async Task<bool> Handle(UpdateProductCommand request, CancellationToken cancellationToken)
@ -82,7 +80,34 @@ public class UpdateProductCommandHandler(IRepositoryWrapper repositoryWrapper, I
await mediator.Send(discountRequest, cancellationToken);
}
}
else
{
var discount = await repositoryWrapper.SetRepository<ProductDiscount>()
.TableNoTracking
.FirstOrDefaultAsync(d => d.ProductId == newEnt.Id && d.IsSpecialOffer, cancellationToken);
if (discount != null)
await mediator.Send(new DeleteDiscountCommand(discount.Id), cancellationToken);
}
await UpdateFaqAsync(newEnt, request.Faqs, cancellationToken);
return true;
}
private async Task UpdateFaqAsync(Product newEnt, Dictionary<string, string> faqs, CancellationToken cancellationToken)
{
var url = newEnt.GetWebSiteUrl();
var oldFaq = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(f => f.Slug == newEnt.Slug, cancellationToken);
var newFaq = await martenRepositoryWrapper.SetRepository<BaseFaq>()
.GetEntityAsync(f => f.Slug == url, cancellationToken);
if (oldFaq != null)
await mediator.Send(new DeleteFaqCommand(oldFaq.Id), cancellationToken);
if (newFaq == null)
await mediator.Send(new CreateFaqCommand(faqs, url, newEnt.EnglishName), cancellationToken);
else
await mediator.Send(new UpdateFaqCommand(newFaq.Id, faqs, url, newEnt.EnglishName), cancellationToken);
}
}

View File

@ -45,6 +45,7 @@
<Using Include="MediatR" />
<Using Include="Microsoft.AspNetCore.Builder" />
<Using Include="Microsoft.AspNetCore.Identity" />
<Using Include="Microsoft.EntityFrameworkCore" />
<Using Include="Microsoft.Extensions.DependencyInjection" />
<Using Include="Microsoft.Extensions.Logging" />
<Using Include="Microsoft.Extensions.Options" />
@ -63,7 +64,9 @@
<Using Include="Netina.Domain.Entities.Products" />
<Using Include="Netina.Domain.Entities.Users" />
<Using Include="Netina.Domain.Enums" />
<Using Include="Netina.Domain.Extensions" />
<Using Include="Netina.Domain.Mappers" />
<Using Include="Netina.Domain.MartenEntities.Faqs" />
<Using Include="Netina.Domain.Models.Claims" />
<Using Include="Netina.Domain.Models.Settings" />
<Using Include="Netina.Repository.Abstracts" />
@ -71,6 +74,7 @@
<Using Include="Netina.Repository.Models" />
<Using Include="Netina.Repository.Repositories.Base" />
<Using Include="Netina.Repository.Repositories.Base.Contracts" />
<Using Include="Netina.Repository.Repositories.Marten" />
<Using Include="Netina.Repository.Services.Abstracts" />
<Using Include="Pluralize.NET" />
<Using Include="System.Diagnostics" />

View File

@ -6,10 +6,13 @@ public interface IMartenRepository<TMartenEntity> : IScopedDependency where TMar
{
Task<List<TMartenEntity>> GetEntitiesAsync(CancellationToken cancellation = default);
Task<List<TMartenEntity>> GetEntitiesAsync(Expression<Func<TMartenEntity, bool>> expression, CancellationToken cancellation = default);
Task<List<TMartenEntity>> GetEntitiesAsync(int page, int count, CancellationToken cancellation);
Task<List<TMartenEntity>> GetEntitiesAsync(Expression<Func<TMartenEntity, bool>> expression, int page, int count, CancellationToken cancellation);
Task<TMartenEntity> GetEntityAsync(Guid id, CancellationToken cancellation = default);
Task<TMartenEntity?> GetEntityAsync(Expression<Func<TMartenEntity, bool>> expression, CancellationToken cancellation = default);
Task AddOrUpdateEntityAsync(TMartenEntity entity, CancellationToken cancellation = default);
Task UpdateEntityAsync(TMartenEntity entity, CancellationToken cancellation = default);
Task RemoveEntityAsync(TMartenEntity entity, CancellationToken cancellation = default);
}

View File

@ -1,44 +1,25 @@
using Microsoft.EntityFrameworkCore;
namespace Netina.Repository.Services;
namespace Netina.Repository.Services;
public class DbInitializerService : IDbInitializerService
{
private readonly IOptionsSnapshot<SiteSettings> _adminUserSeedOptions;
private readonly ApplicationContext _context;
private readonly ILogger<DbInitializerService> _logger;
private readonly IRepositoryWrapper _repositoryWrapper;
private readonly RoleManager<ApplicationRole> _roleManager;
private readonly UserManager<ApplicationUser> _userManager;
public DbInitializerService(
public class DbInitializerService(
ApplicationContext context,
RoleManager<ApplicationRole> roleManager,
UserManager<ApplicationUser> userManager,
IOptionsSnapshot<SiteSettings> adminUserSeedOptions,
ILogger<DbInitializerService> logger,
IRepositoryWrapper repositoryWrapper)
: IDbInitializerService
{
_context = context;
_roleManager = roleManager;
_userManager = userManager;
_adminUserSeedOptions = adminUserSeedOptions;
_logger = logger;
_repositoryWrapper = repositoryWrapper;
}
public void Initialize()
{
try
{
_context.Database.Migrate();
_context.Database.ExecuteSqlRaw("CREATE EXTENSION IF NOT EXISTS pg_trgm");
_logger.LogInformation("Migration SUCCESS !!!!");
context.Database.Migrate();
context.Database.ExecuteSqlRaw("CREATE EXTENSION IF NOT EXISTS pg_trgm");
logger.LogInformation("Migration SUCCESS !!!!");
}
catch (Exception e)
{
_logger.LogError(e, e.Message);
logger.LogError(e, e.Message);
}
}
@ -47,9 +28,9 @@ public class DbInitializerService : IDbInitializerService
try
{
await SeedRoles();
var seedAdmin = _adminUserSeedOptions.Value.UserSetting;
var manager = _adminUserSeedOptions.Value.Manager;
var user = await _userManager.FindByNameAsync(seedAdmin.Username);
var seedAdmin = adminUserSeedOptions.Value.UserSetting;
var manager = adminUserSeedOptions.Value.Manager;
var user = await userManager.FindByNameAsync(seedAdmin.Username);
if (user == null)
{
var adminUser = new ApplicationUser
@ -65,17 +46,17 @@ public class DbInitializerService : IDbInitializerService
PhoneNumber = seedAdmin.Phone,
BirthDate = DateTime.Now.AddYears(-23)
};
var adminUserResult = await _userManager.CreateAsync(adminUser, seedAdmin.Password);
_repositoryWrapper.SetRepository<Manager>()
var adminUserResult = await userManager.CreateAsync(adminUser, seedAdmin.Password);
repositoryWrapper.SetRepository<Manager>()
.Add(new Manager
{
UserId = adminUser.Id
});
await _repositoryWrapper.SaveChangesAsync(default);
if (adminUserResult.Succeeded) await _userManager.AddToRoleAsync(adminUser, seedAdmin.RoleName);
await repositoryWrapper.SaveChangesAsync(default);
if (adminUserResult.Succeeded) await userManager.AddToRoleAsync(adminUser, seedAdmin.RoleName);
}
var mahanUser = await _userManager.FindByNameAsync(manager.Username);
var mahanUser = await userManager.FindByNameAsync(manager.Username);
if (mahanUser == null)
{
mahanUser = new ApplicationUser
@ -91,14 +72,14 @@ public class DbInitializerService : IDbInitializerService
PhoneNumber = manager.Phone,
BirthDate = DateTime.Now.AddYears(-23)
};
var adminUserResult = await _userManager.CreateAsync(mahanUser, seedAdmin.Password);
_repositoryWrapper.SetRepository<Manager>()
var adminUserResult = await userManager.CreateAsync(mahanUser, seedAdmin.Password);
repositoryWrapper.SetRepository<Manager>()
.Add(new Manager
{
UserId = mahanUser.Id
});
await _repositoryWrapper.SaveChangesAsync(default);
if (adminUserResult.Succeeded) await _userManager.AddToRoleAsync(mahanUser, "Manager");
await repositoryWrapper.SaveChangesAsync(default);
if (adminUserResult.Succeeded) await userManager.AddToRoleAsync(mahanUser, "Manager");
}
}
catch (Exception e)
@ -110,8 +91,8 @@ public class DbInitializerService : IDbInitializerService
public async Task SeedRoles()
{
var seedAdmin = _adminUserSeedOptions.Value.UserSetting;
var rootRole = await _roleManager.FindByNameAsync(seedAdmin.RoleName);
var seedAdmin = adminUserSeedOptions.Value.UserSetting;
var rootRole = await roleManager.FindByNameAsync(seedAdmin.RoleName);
if (rootRole == null)
{
rootRole = new ApplicationRole
@ -120,21 +101,21 @@ public class DbInitializerService : IDbInitializerService
EnglishName = seedAdmin.RoleName,
Description = "root admin role"
};
var adminRoleResult = await _roleManager.CreateAsync(rootRole);
var adminRoleResult = await roleManager.CreateAsync(rootRole);
foreach (var claim in ApplicationClaims.AllClaims)
await _roleManager.AddClaimAsync(rootRole, claim);
await roleManager.AddClaimAsync(rootRole, claim);
}
else
{
foreach (var claim in ApplicationClaims.AllClaims)
{
var claims = await _roleManager.GetClaimsAsync(rootRole);
var claims = await roleManager.GetClaimsAsync(rootRole);
if (claims.FirstOrDefault(c => c.Value == claim.Value) == null)
await _roleManager.AddClaimAsync(rootRole, claim);
await roleManager.AddClaimAsync(rootRole, claim);
}
}
var managerRole = await _roleManager.FindByNameAsync("Manager");
var managerRole = await roleManager.FindByNameAsync("Manager");
if (managerRole == null)
{
managerRole = new ApplicationRole
@ -144,21 +125,21 @@ public class DbInitializerService : IDbInitializerService
PersianName = "مدیریتـــ",
Description = "admin role"
};
var adminRoleResult = await _roleManager.CreateAsync(managerRole);
var adminRoleResult = await roleManager.CreateAsync(managerRole);
foreach (var claim in ApplicationClaims.AllClaims)
await _roleManager.AddClaimAsync(managerRole, claim);
await roleManager.AddClaimAsync(managerRole, claim);
}
else
{
foreach (var claim in ApplicationClaims.AllClaims)
{
var claims = await _roleManager.GetClaimsAsync(managerRole);
var claims = await roleManager.GetClaimsAsync(managerRole);
if (claims.FirstOrDefault(c => c.Value == claim.Value) == null)
await _roleManager.AddClaimAsync(managerRole, claim);
await roleManager.AddClaimAsync(managerRole, claim);
}
}
var customerRole = await _roleManager.FindByNameAsync("Customer");
var customerRole = await roleManager.FindByNameAsync("Customer");
if (customerRole == null)
{
customerRole = new ApplicationRole
@ -168,17 +149,17 @@ public class DbInitializerService : IDbInitializerService
EnglishName = "Customer",
};
var customerRoleResult = await _roleManager.CreateAsync(customerRole);
var customerRoleResult = await roleManager.CreateAsync(customerRole);
foreach (var claim in ApplicationClaims.CustomerClaims)
await _roleManager.AddClaimAsync(customerRole, claim);
await roleManager.AddClaimAsync(customerRole, claim);
}
else
{
foreach (var claim in ApplicationClaims.CustomerClaims)
{
var claims = await _roleManager.GetClaimsAsync(customerRole);
var claims = await roleManager.GetClaimsAsync(customerRole);
if (claims.FirstOrDefault(c => c.Value == claim.Value) == null)
await _roleManager.AddClaimAsync(customerRole, claim);
await roleManager.AddClaimAsync(customerRole, claim);
}
}
}