Refactor and enhance product and order handling
- Updated `DiscountActionDialogBoxViewModel` and `FastProductCreateDialogBoxViewModel` to create command objects directly from properties and improved error handling. - Added meta tag management UI and logic in `ProductActionDialogBox.razor` and `ProductActionDialogBoxViewModel`. - Increased max file read stream size to 8 MB in `StorageDialogBoxViewModel`. - Incremented `AssemblyVersion` and `FileVersion` to `1.7.20.34` in `Netina.AdminPanel.PWA.csproj`. - Updated `BrandsPage.razor` and `BrandsPageViewModel` for pagination and service injection. - Updated `CategoriesPageViewModel` to create command objects directly from properties. - Updated `ProductsPage.razor` for service injection and added a button for product details. - Updated `ICrudApiRest` and `ICrudDtoApiRest` interfaces to use generic `Create` methods. - Updated `appsettings.Development.json` for `StorageBaseUrl` and commented out `IsShop`. - Added new project `AppHost.csproj` targeting .NET 8.0 with Aspire hosting. - Added new `appsettings.Development.json` and `appsettings.json` for logging. - Added new `Program.cs` to create and run a distributed application. - Added new `launchSettings.json` for application launch settings. - Added `Extensions.cs` for common .NET Aspire services. - Added new project `ServiceDefaults.csproj` for shared service defaults. - Introduced `ProductMetaTag` class and related migration for meta tag handling. - Updated `OrderController.cs` for additional authorization requirements. - Updated target frameworks to `net8.0` in various projects. - Enhanced `SiteMapService.cs` to include brand site maps. - Added new properties to DTOs for customer and meta tag handling. - Enhanced `Product` class with meta tag management methods. - Refactored `OrderMapper.g.cs` and `ProductMapper.g.cs` for improved mapping logic. - Enhanced command handlers to manage meta tags. - Added `ICurrentUserService` for user permissions in query handlers. - Refactored `StorageService.cs` for paginated storage file fetching.subProduct
parent
82f9d604da
commit
53dc2eac0c
|
@ -16,7 +16,10 @@ public class OrderController : ICarterModule
|
||||||
|
|
||||||
group.MapGet("{id}", GetAsync)
|
group.MapGet("{id}", GetAsync)
|
||||||
.WithDisplayName("Get Order")
|
.WithDisplayName("Get Order")
|
||||||
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ViewAllOrders, ApplicationPermission.ManageOrders))
|
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission,
|
||||||
|
ApplicationPermission.ViewAllOrders,
|
||||||
|
ApplicationPermission.ManageOrders,
|
||||||
|
ApplicationPermission.ViewMineOrders))
|
||||||
.HasApiVersion(1.0);
|
.HasApiVersion(1.0);
|
||||||
|
|
||||||
group.MapPost("{id}/confirm", ConfirmOrderStepAsync)
|
group.MapPost("{id}/confirm", ConfirmOrderStepAsync)
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<InvariantGlobalization>true</InvariantGlobalization>
|
<InvariantGlobalization>true</InvariantGlobalization>
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
<AssemblyVersion>1.6.18.28</AssemblyVersion>
|
<AssemblyVersion>1.7.20.34</AssemblyVersion>
|
||||||
<FileVersion>1.6.18.28</FileVersion>
|
<FileVersion>1.7.20.34</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<!--<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
@ -12,9 +12,9 @@
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.2" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.2" />
|
||||||
</ItemGroup>-->
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<!--<PropertyGroup>
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<LangVersion>10</LangVersion>
|
<LangVersion>10</LangVersion>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.3.1" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.3.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>-->
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Using Include="MD.PersianDateTime.Standard" />
|
<Using Include="MD.PersianDateTime.Standard" />
|
||||||
|
|
|
@ -99,7 +99,7 @@ public class SiteMapService(
|
||||||
await CreateCategoriesSiteMapsAsync();
|
await CreateCategoriesSiteMapsAsync();
|
||||||
await CreateProductsSiteMapsAsync();
|
await CreateProductsSiteMapsAsync();
|
||||||
await CreateBlogsSiteMapsAsync();
|
await CreateBlogsSiteMapsAsync();
|
||||||
//await CreateBrandsSiteMapsAsync();
|
await CreateBrandsSiteMapsAsync();
|
||||||
await CreateBlogCategoriesSiteMapsAsync();
|
await CreateBlogCategoriesSiteMapsAsync();
|
||||||
await CreatePagesSiteMapsAsync();
|
await CreatePagesSiteMapsAsync();
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ public class OrderLDto : BaseDto<OrderLDto,Order>
|
||||||
public string DiscountCode { get; set; } = string.Empty;
|
public string DiscountCode { get; set; } = string.Empty;
|
||||||
public long TotalPriceWithoutDiscount => TotalPrice + DiscountPrice;
|
public long TotalPriceWithoutDiscount => TotalPrice + DiscountPrice;
|
||||||
|
|
||||||
|
public Guid CustomerId { get; set; }
|
||||||
public string CustomerFullName { get; set; } = string.Empty;
|
public string CustomerFullName { get; set; } = string.Empty;
|
||||||
public string CustomerPhoneNumber { get; set; } = string.Empty;
|
public string CustomerPhoneNumber { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ public class ProductLDto : BaseDto<ProductLDto,Product>
|
||||||
|
|
||||||
public List<SpecificationSDto> Specifications { get; set; } = new();
|
public List<SpecificationSDto> Specifications { get; set; } = new();
|
||||||
public List<StorageFileSDto> Files { get; set; } = new();
|
public List<StorageFileSDto> Files { get; set; } = new();
|
||||||
|
public List<MetaTagSDto> MetaTags { get; set; } = new();
|
||||||
|
|
||||||
public DiscountSDto? SpecialOffer { get; set; }
|
public DiscountSDto? SpecialOffer { get; set; }
|
||||||
public Guid AuthorId { get; set; }
|
public Guid AuthorId { get; set; }
|
||||||
|
|
|
@ -21,4 +21,5 @@ public class OrderSDto : BaseDto<OrderSDto, Order>
|
||||||
public string CustomerFullName { get; set; } = string.Empty;
|
public string CustomerFullName { get; set; } = string.Empty;
|
||||||
public string CustomerPhoneNumber { get; set; } = string.Empty;
|
public string CustomerPhoneNumber { get; set; } = string.Empty;
|
||||||
public Guid CustomerId { get; set; }
|
public Guid CustomerId { get; set; }
|
||||||
|
public string DeliveryTrackingCode { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ public partial class ProductCategoryMetaTag : MetaTag
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProductCategoryMetaTag(string type, string value, Guid productCategoryId) : base(type, value)
|
public ProductCategoryMetaTag(string type, string value, Guid productCategoryId) : base(type, value)
|
||||||
{
|
{
|
||||||
ProductCategoryId = productCategoryId;
|
ProductCategoryId = productCategoryId;
|
||||||
|
|
|
@ -60,6 +60,9 @@ public partial class Product
|
||||||
Specifications.Add(ent);
|
Specifications.Add(ent);
|
||||||
return ent;
|
return ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddMetaTag(string key, string value)
|
||||||
|
=> MetaTags.Add(ProductMetaTag.Create(key, value, Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class ProductComment
|
public partial class ProductComment
|
||||||
|
@ -67,6 +70,11 @@ public partial class ProductComment
|
||||||
public static ProductComment Create(string title, string content, float rate, bool isBuyer, bool isAdmin, Guid userId, Guid productId)
|
public static ProductComment Create(string title, string content, float rate, bool isBuyer, bool isAdmin, Guid userId, Guid productId)
|
||||||
=> new(title, content, rate, isBuyer, isAdmin, userId, productId);
|
=> new(title, content, rate, isBuyer, isAdmin, userId, productId);
|
||||||
}
|
}
|
||||||
|
public partial class ProductMetaTag
|
||||||
|
{
|
||||||
|
public static ProductMetaTag Create(string key, string value, Guid productId)
|
||||||
|
=> new ProductMetaTag(key, value, productId);
|
||||||
|
}
|
||||||
|
|
||||||
public partial class ProductStorageFile
|
public partial class ProductStorageFile
|
||||||
{
|
{
|
||||||
|
|
|
@ -85,5 +85,7 @@ public partial class Product : ApiEntity
|
||||||
public List<ProductComment> Comments { get; internal set; } = new();
|
public List<ProductComment> Comments { get; internal set; } = new();
|
||||||
public List<ProductStorageFile> Files { get; internal set; } = new();
|
public List<ProductStorageFile> Files { get; internal set; } = new();
|
||||||
|
|
||||||
|
public List<ProductMetaTag> MetaTags { get; internal set; } = new();
|
||||||
|
|
||||||
public List<OrderProduct> OrderProducts { get; internal set; } = new();
|
public List<OrderProduct> OrderProducts { get; internal set; } = new();
|
||||||
}
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
namespace Netina.Domain.Entities.Products;
|
||||||
|
|
||||||
|
public partial class ProductMetaTag : MetaTag
|
||||||
|
{
|
||||||
|
public ProductMetaTag()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProductMetaTag(string type, string value, Guid productId) : base(type, value)
|
||||||
|
{
|
||||||
|
ProductId = productId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid ProductId { get; set; }
|
||||||
|
public Product? Product { get; set; }
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,6 @@
|
||||||
|
namespace Netina.Domain.Mappers
|
||||||
|
{
|
||||||
|
public static partial class ProductMetaTagMapper
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -100,6 +100,7 @@ public class MapsterRegister : IRegister
|
||||||
config.NewConfig<Order, OrderSDto>()
|
config.NewConfig<Order, OrderSDto>()
|
||||||
.Map("CustomerFullName", o => o.Customer != null && o.Customer.User != null ? o.Customer.User.FirstName + " " + o.Customer.User.LastName : string.Empty)
|
.Map("CustomerFullName", o => o.Customer != null && o.Customer.User != null ? o.Customer.User.FirstName + " " + o.Customer.User.LastName : string.Empty)
|
||||||
.Map("CustomerPhoneNumber", o => o.Customer != null && o.Customer.User != null ? o.Customer.User.PhoneNumber : string.Empty)
|
.Map("CustomerPhoneNumber", o => o.Customer != null && o.Customer.User != null ? o.Customer.User.PhoneNumber : string.Empty)
|
||||||
|
.Map(d=>d.DeliveryTrackingCode,o=>o.OrderDelivery!=null ? o.OrderDelivery.TrackingCode : string.Empty)
|
||||||
.IgnoreNullValues(false)
|
.IgnoreNullValues(false)
|
||||||
.TwoWays();
|
.TwoWays();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<!--<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
@ -15,9 +15,9 @@
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.8" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="8.0.8" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="8.0.8" />
|
||||||
<PackageReference Include="PropertyChanged.Fody" Version="4.1.0" />
|
<PackageReference Include="PropertyChanged.Fody" Version="4.1.0" />
|
||||||
</ItemGroup>-->
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<!--<PropertyGroup>
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<LangVersion>10</LangVersion>
|
<LangVersion>10</LangVersion>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.0" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.0" />
|
||||||
<PackageReference Include="PropertyChanged.Fody" Version="4.1.0" />
|
<PackageReference Include="PropertyChanged.Fody" Version="4.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>-->
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -81,7 +81,7 @@ public class StorageService(IOptionsSnapshot<SiteSettings> snapshot) : IStorageS
|
||||||
public async Task<List<StorageFileSDto>> GetStorageFiles(StorageFileType fileType)
|
public async Task<List<StorageFileSDto>> GetStorageFiles(StorageFileType fileType)
|
||||||
{
|
{
|
||||||
var client = GetClientAsync();
|
var client = GetClientAsync();
|
||||||
ListObjectsRequest request = new() { BucketName = _bucketName};
|
ListObjectsV2Request request = new() { BucketName = _bucketName, MaxKeys = 3000 };
|
||||||
switch (fileType)
|
switch (fileType)
|
||||||
{
|
{
|
||||||
case StorageFileType.Image:
|
case StorageFileType.Image:
|
||||||
|
@ -93,33 +93,22 @@ public class StorageService(IOptionsSnapshot<SiteSettings> snapshot) : IStorageS
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
var files = new List<StorageFileSDto>();
|
var pagination = client.Paginators.ListObjectsV2(request);
|
||||||
do
|
var s3Files = new List<S3Object>();
|
||||||
|
await foreach (var listObjectsV2Response in pagination.Responses)
|
||||||
{
|
{
|
||||||
ListObjectsResponse response = await client.ListObjectsAsync(request);
|
s3Files.AddRange(listObjectsV2Response.S3Objects);
|
||||||
|
}
|
||||||
|
|
||||||
// Process the response.
|
var files = s3Files
|
||||||
foreach (var s3Object in response.S3Objects.Where(s=>s.Size>0))
|
.OrderByDescending(s => s.LastModified)
|
||||||
|
.Take(100)
|
||||||
|
.Select(s => new StorageFileSDto
|
||||||
{
|
{
|
||||||
files.Add(new StorageFileSDto
|
FileLocation = s.Key,
|
||||||
{
|
FileName = s.Key.Split('/').Last()
|
||||||
FileLocation = s3Object.Key,
|
}).ToList();
|
||||||
FileName = s3Object.Key.Split('/').Last()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the response is truncated, set the marker to get the next
|
return files.ToList();
|
||||||
// set of keys.
|
|
||||||
if (response.IsTruncated)
|
|
||||||
{
|
|
||||||
request.Marker = response.NextMarker;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
request = null;
|
|
||||||
}
|
|
||||||
} while (request != null);
|
|
||||||
|
|
||||||
return files.OrderByDescending(o=>o.CreatedAt).ToList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,19 +1,35 @@
|
||||||
using Netina.Domain.Entities.Orders;
|
using Netina.Domain.Entities.Orders;
|
||||||
|
using Netina.Repository.Abstracts;
|
||||||
|
|
||||||
namespace Netina.Repository.Handlers.Orders;
|
namespace Netina.Repository.Handlers.Orders;
|
||||||
|
|
||||||
public class GetOrderLDtoQueryHandler(IRepositoryWrapper repositoryWrapper)
|
public class GetOrderLDtoQueryHandler(IRepositoryWrapper repositoryWrapper,ICurrentUserService currentUserService)
|
||||||
: IRequestHandler<GetOrderLDtoQuery, OrderLDto>
|
: IRequestHandler<GetOrderLDtoQuery, OrderLDto>
|
||||||
{
|
{
|
||||||
public async Task<OrderLDto> Handle(GetOrderLDtoQuery request, CancellationToken cancellationToken)
|
public async Task<OrderLDto> Handle(GetOrderLDtoQuery request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
if (currentUserService.Permissions == null)
|
||||||
|
throw new BaseApiException(ApiResultStatusCode.UnAuthorized);
|
||||||
if (request.Id == default)
|
if (request.Id == default)
|
||||||
throw new AppException("Order id is null");
|
throw new AppException("Order id is null");
|
||||||
|
|
||||||
var order = await repositoryWrapper.SetRepository<Order>()
|
var order = await repositoryWrapper.SetRepository<Order>()
|
||||||
.TableNoTracking
|
.TableNoTracking
|
||||||
.Where(o => o.Id == request.Id)
|
.Where(o => o.Id == request.Id)
|
||||||
.Select(OrderMapper.ProjectToLDto)
|
.Select(OrderMapper.ProjectToLDto)
|
||||||
.FirstOrDefaultAsync(cancellationToken);
|
.FirstOrDefaultAsync(cancellationToken);
|
||||||
|
if (currentUserService.Permissions.Contains(ApplicationPermission.ViewMineOrders) && !currentUserService.Permissions.Contains(ApplicationPermission.ViewAllOrders))
|
||||||
|
{
|
||||||
|
if (currentUserService.UserId.IsNullOrEmpty() || !Guid.TryParse(currentUserService.UserId, out Guid userId))
|
||||||
|
throw new BaseApiException(ApiResultStatusCode.UnAuthorized);
|
||||||
|
|
||||||
|
var customer = await repositoryWrapper.SetRepository<Customer>()
|
||||||
|
.TableNoTracking
|
||||||
|
.FirstOrDefaultAsync(c => c.UserId == userId, cancellationToken);
|
||||||
|
|
||||||
|
if (customer == null || order.CustomerId != customer.Id)
|
||||||
|
throw new BaseApiException(ApiResultStatusCode.UnAuthorized);
|
||||||
|
}
|
||||||
if (order == null)
|
if (order == null)
|
||||||
throw new AppException("Order not found", ApiResultStatusCode.NotFound);
|
throw new AppException("Order not found", ApiResultStatusCode.NotFound);
|
||||||
return order;
|
return order;
|
||||||
|
|
|
@ -2,25 +2,25 @@
|
||||||
|
|
||||||
namespace Netina.Repository.Handlers.Orders;
|
namespace Netina.Repository.Handlers.Orders;
|
||||||
|
|
||||||
public class GetOrderQueryHandler(IRepositoryWrapper repositoryWrapper) : IRequestHandler<GetOrderQuery, Order>
|
public class GetOrderQueryHandler(IRepositoryWrapper repositoryWrapper, ICurrentUserService currentUserService) : IRequestHandler<GetOrderQuery, Order>
|
||||||
{
|
{
|
||||||
public async Task<Order> Handle(GetOrderQuery request, CancellationToken cancellationToken)
|
public async Task<Order> Handle(GetOrderQuery request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
|
||||||
var order = await repositoryWrapper.SetRepository<Order>()
|
var order = await repositoryWrapper.SetRepository<Order>()
|
||||||
.TableNoTracking
|
.TableNoTracking
|
||||||
.FirstOrDefaultAsync(o => o.Id == request.Id, cancellationToken);
|
.FirstOrDefaultAsync(o => o.Id == request.Id, cancellationToken);
|
||||||
|
|
||||||
if (order == null)
|
if (order == null)
|
||||||
throw new AppException("Order not found", ApiResultStatusCode.NotFound);
|
throw new AppException("Order not found", ApiResultStatusCode.NotFound);
|
||||||
|
|
||||||
var orderProducts = await repositoryWrapper.SetRepository<OrderProduct>()
|
var orderProducts = await repositoryWrapper.SetRepository<OrderProduct>()
|
||||||
.TableNoTracking
|
.TableNoTracking
|
||||||
.Where(op => op.OrderId == order.Id)
|
.Where(op => op.OrderId == order.Id)
|
||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
orderProducts.ForEach(op => order.AddOrderProduct(op));
|
orderProducts.ForEach(op => order.AddOrderProduct(op));
|
||||||
|
|
||||||
var orderDelivery= await repositoryWrapper.SetRepository<OrderDelivery>()
|
var orderDelivery = await repositoryWrapper.SetRepository<OrderDelivery>()
|
||||||
.TableNoTracking
|
.TableNoTracking
|
||||||
.FirstOrDefaultAsync(od => od.OrderId == request.Id, cancellationToken);
|
.FirstOrDefaultAsync(od => od.OrderId == request.Id, cancellationToken);
|
||||||
if (orderDelivery != null)
|
if (orderDelivery != null)
|
||||||
|
|
|
@ -56,6 +56,9 @@ public class CreateProductCommandHandler(IRepositoryWrapper repositoryWrapper,IM
|
||||||
|
|
||||||
await UpdateFaqAsync(ent, request.Faqs, cancellationToken);
|
await UpdateFaqAsync(ent, request.Faqs, cancellationToken);
|
||||||
|
|
||||||
|
foreach (var (key, value) in request.MetaTags)
|
||||||
|
ent.AddMetaTag(key, value);
|
||||||
|
|
||||||
return ent.AdaptToLDto();
|
return ent.AdaptToLDto();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ public class UpdateProductCommandHandler(IRepositoryWrapper repositoryWrapper,IM
|
||||||
newEnt.CreatedAt = ent.CreatedAt;
|
newEnt.CreatedAt = ent.CreatedAt;
|
||||||
newEnt.CreatedBy = ent.CreatedBy;
|
newEnt.CreatedBy = ent.CreatedBy;
|
||||||
|
|
||||||
|
//Check Specifications
|
||||||
var dbSpecifications = await repositoryWrapper.SetRepository<Specification>().TableNoTracking
|
var dbSpecifications = await repositoryWrapper.SetRepository<Specification>().TableNoTracking
|
||||||
.Where(s => s.ProductId == ent.Id).ToListAsync(cancellationToken);
|
.Where(s => s.ProductId == ent.Id).ToListAsync(cancellationToken);
|
||||||
foreach (var dbSpecification in dbSpecifications)
|
foreach (var dbSpecification in dbSpecifications)
|
||||||
|
@ -44,8 +45,22 @@ public class UpdateProductCommandHandler(IRepositoryWrapper repositoryWrapper,IM
|
||||||
newEnt.AddSpecification(specification.Title, specification.Detail, specification.Value, specification.IsFeature, specification.ParentId);
|
newEnt.AddSpecification(specification.Title, specification.Detail, specification.Value, specification.IsFeature, specification.ParentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Check MetaTags
|
||||||
|
var dbMetaTags = await repositoryWrapper.SetRepository<ProductMetaTag>()
|
||||||
|
.TableNoTracking
|
||||||
|
.Where(f => f.ProductId == ent.Id)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
foreach (var feature in dbMetaTags.Where(feature => request.MetaTags.Any(f => f.Key == feature.Type) == false))
|
||||||
|
{
|
||||||
|
repositoryWrapper.SetRepository<ProductMetaTag>()
|
||||||
|
.Delete(feature);
|
||||||
|
await repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
foreach (var (key, value) in request.MetaTags.Where(f => dbMetaTags.Any(dbf => dbf.Type == f.Key) == false))
|
||||||
|
newEnt.AddMetaTag(key, value);
|
||||||
|
|
||||||
|
|
||||||
|
//Check Files
|
||||||
var dbFiles = await repositoryWrapper.SetRepository<ProductStorageFile>().TableNoTracking
|
var dbFiles = await repositoryWrapper.SetRepository<ProductStorageFile>().TableNoTracking
|
||||||
.Where(s => s.ProductId == ent.Id).ToListAsync(cancellationToken);
|
.Where(s => s.ProductId == ent.Id).ToListAsync(cancellationToken);
|
||||||
foreach (var dbFile in dbFiles)
|
foreach (var dbFile in dbFiles)
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace NetinaShop.Repository.Migrations
|
||||||
table: "Products",
|
table: "Products",
|
||||||
type: "uuid",
|
type: "uuid",
|
||||||
nullable: false,
|
nullable: false,
|
||||||
defaultValue: new Guid("8723f1d2-e091-4812-9110-5161c9e23586"));
|
defaultValue: new Guid("11c47231-4f8b-4a73-b848-d2edf3c2d9ab"));
|
||||||
|
|
||||||
migrationBuilder.AddColumn<Guid>(
|
migrationBuilder.AddColumn<Guid>(
|
||||||
name: "AuthorId",
|
name: "AuthorId",
|
||||||
|
@ -25,7 +25,7 @@ namespace NetinaShop.Repository.Migrations
|
||||||
table: "Blogs",
|
table: "Blogs",
|
||||||
type: "uuid",
|
type: "uuid",
|
||||||
nullable: false,
|
nullable: false,
|
||||||
defaultValue: new Guid("8723f1d2-e091-4812-9110-5161c9e23586"));
|
defaultValue: new Guid("11c47231-4f8b-4a73-b848-d2edf3c2d9ab"));
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_Products_AuthorId",
|
name: "IX_Products_AuthorId",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,57 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NetinaShop.Repository.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddProductMetaTag : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "ProductId",
|
||||||
|
schema: "public",
|
||||||
|
table: "MetaTags",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_MetaTags_ProductId",
|
||||||
|
schema: "public",
|
||||||
|
table: "MetaTags",
|
||||||
|
column: "ProductId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_MetaTags_Products_ProductId",
|
||||||
|
schema: "public",
|
||||||
|
table: "MetaTags",
|
||||||
|
column: "ProductId",
|
||||||
|
principalSchema: "public",
|
||||||
|
principalTable: "Products",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_MetaTags_Products_ProductId",
|
||||||
|
schema: "public",
|
||||||
|
table: "MetaTags");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_MetaTags_ProductId",
|
||||||
|
schema: "public",
|
||||||
|
table: "MetaTags");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ProductId",
|
||||||
|
schema: "public",
|
||||||
|
table: "MetaTags");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1698,6 +1698,18 @@ namespace NetinaShop.Repository.Migrations
|
||||||
b.HasDiscriminator().HasValue("ProductCategoryMetaTag");
|
b.HasDiscriminator().HasValue("ProductCategoryMetaTag");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Netina.Domain.Entities.Products.ProductMetaTag", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("Netina.Domain.Entities.Seo.MetaTag");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("ProductMetaTag");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogStorageFile", b =>
|
modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogStorageFile", b =>
|
||||||
{
|
{
|
||||||
b.HasBaseType("Netina.Domain.Entities.StorageFiles.StorageFile");
|
b.HasBaseType("Netina.Domain.Entities.StorageFiles.StorageFile");
|
||||||
|
@ -2070,6 +2082,16 @@ namespace NetinaShop.Repository.Migrations
|
||||||
b.Navigation("ProductCategory");
|
b.Navigation("ProductCategory");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Netina.Domain.Entities.Products.ProductMetaTag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Netina.Domain.Entities.Products.Product", "Product")
|
||||||
|
.WithMany("MetaTags")
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogStorageFile", b =>
|
modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogStorageFile", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Netina.Domain.Entities.Blogs.Blog", "Blog")
|
b.HasOne("Netina.Domain.Entities.Blogs.Blog", "Blog")
|
||||||
|
@ -2161,6 +2183,8 @@ namespace NetinaShop.Repository.Migrations
|
||||||
|
|
||||||
b.Navigation("Files");
|
b.Navigation("Files");
|
||||||
|
|
||||||
|
b.Navigation("MetaTags");
|
||||||
|
|
||||||
b.Navigation("OrderProducts");
|
b.Navigation("OrderProducts");
|
||||||
|
|
||||||
b.Navigation("Specifications");
|
b.Navigation("Specifications");
|
||||||
|
|
Loading…
Reference in New Issue