diff --git a/.version b/.version index d34ae26..f6cabaf 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -1.5.18.27 \ No newline at end of file +1.6.18.28 \ No newline at end of file diff --git a/Netina.Api/Controllers/CustomerController.cs b/Netina.Api/Controllers/CustomerController.cs new file mode 100644 index 0000000..2954d5e --- /dev/null +++ b/Netina.Api/Controllers/CustomerController.cs @@ -0,0 +1,17 @@ +namespace Netina.Api.Controllers; + +public class CustomerController : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + var group = app.NewVersionedApi("Customer").MapGroup("api/customer") + .RequireAuthorization(builder=>builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser()); + + group.MapGet("", GetCustomersAsync) + .WithDisplayName("Get Customers") + .HasApiVersion(1.0); + } + + private async Task GetCustomersAsync([FromQuery] int page, [FromQuery] int? count, [FromServices] IMediator mediator, CancellationToken cancellationToken) + => TypedResults.Ok(true); +} \ No newline at end of file diff --git a/Netina.Api/Netina.Api.csproj b/Netina.Api/Netina.Api.csproj index dd2cbfc..8983fe1 100644 --- a/Netina.Api/Netina.Api.csproj +++ b/Netina.Api/Netina.Api.csproj @@ -6,8 +6,8 @@ enable true Linux - 1.5.18.27 - 1.5.18.27 + 1.6.18.28 + 1.6.18.28 diff --git a/Netina.Common/Netina.Common.csproj b/Netina.Common/Netina.Common.csproj index a3069aa..486e5a7 100644 --- a/Netina.Common/Netina.Common.csproj +++ b/Netina.Common/Netina.Common.csproj @@ -1,6 +1,6 @@  - + - + diff --git a/Netina.Core/BaseServices/SiteMapService.cs b/Netina.Core/BaseServices/SiteMapService.cs index 894ff89..3d8981a 100644 --- a/Netina.Core/BaseServices/SiteMapService.cs +++ b/Netina.Core/BaseServices/SiteMapService.cs @@ -1,11 +1,8 @@ using System.IO.Compression; using System.Net; -using System.Web; using System.Xml; using Netina.Core.Models; -using Netina.Domain.Entities.Brands; using Netina.Domain.Entities.ProductCategories; -using Netina.Domain.Entities.Products; namespace Netina.Core.BaseServices; @@ -14,8 +11,7 @@ public class SiteMapService( IOptionsSnapshot snapshot, IUploadFileService uploadFileService, IRepositoryWrapper repositoryWrapper, - IPageService pageService) - : ISiteMapService + IPageService pageService) : ISiteMapService { private readonly SiteSettings _siteSetting = snapshot.Value; diff --git a/Netina.Domain/CommandQueries/Queries/CustomerQueries.cs b/Netina.Domain/CommandQueries/Queries/CustomerQueries.cs new file mode 100644 index 0000000..9120b2e --- /dev/null +++ b/Netina.Domain/CommandQueries/Queries/CustomerQueries.cs @@ -0,0 +1,3 @@ +namespace Netina.Domain.CommandQueries.Queries; + +public record GetCustomersQuery(int Page = 0, int Count = Refers.SizeM) : IRequest>; \ No newline at end of file diff --git a/Netina.Domain/Dtos/LargDtos/ProductCategoryLDto.cs b/Netina.Domain/Dtos/LargDtos/ProductCategoryLDto.cs index aa4ba9a..f251cb1 100644 --- a/Netina.Domain/Dtos/LargDtos/ProductCategoryLDto.cs +++ b/Netina.Domain/Dtos/LargDtos/ProductCategoryLDto.cs @@ -10,4 +10,5 @@ public class ProductCategoryLDto : BaseDto public bool IsMain { get; set; } public List Children { get; set; } = new(); public List Files { get; internal set; } = new(); + public List MetaTags { get; set; } = new(); } \ No newline at end of file diff --git a/Netina.Domain/Dtos/ResponseDtos/GetProductsResponseDto.cs b/Netina.Domain/Dtos/ResponseDtos/GetProductsResponseDto.cs index 31a2568..007b4c6 100644 --- a/Netina.Domain/Dtos/ResponseDtos/GetProductsResponseDto.cs +++ b/Netina.Domain/Dtos/ResponseDtos/GetProductsResponseDto.cs @@ -9,10 +9,19 @@ public class GetProductsResponseDto public PagerResponseDto Pager { get; set; } = new PagerResponseDto(); public FilterResponseDto Filters { get; set; } = new FilterResponseDto(); + + public SeoResponseDto Seo { get; set; } = new SeoResponseDto(); } public class FilterResponseDto { public PriceFilterDto Price { get; set; } = new PriceFilterDto(); public ExpressDeliveryFilter ExpressDelivery { get; set; } = new ExpressDeliveryFilter(); +} + +public class SeoResponseDto +{ + public string Description { get; set; } = string.Empty; + public string Title { get; set; } = string.Empty; + public Dictionary MetaTags { get; set; } = new(); } \ No newline at end of file diff --git a/Netina.Domain/Dtos/SmallDtos/MetaTagSDto.cs b/Netina.Domain/Dtos/SmallDtos/MetaTagSDto.cs new file mode 100644 index 0000000..0b19168 --- /dev/null +++ b/Netina.Domain/Dtos/SmallDtos/MetaTagSDto.cs @@ -0,0 +1,7 @@ +namespace Netina.Domain.Dtos.SmallDtos; + +public class MetaTagSDto : BaseDto +{ + public string Type { get; set; } = string.Empty; + public string Value { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/Netina.Domain/Entities/ProductCategories/ProductCategory.Aggregate.cs b/Netina.Domain/Entities/ProductCategories/ProductCategory.Aggregate.cs index 1df9afe..b886078 100644 --- a/Netina.Domain/Entities/ProductCategories/ProductCategory.Aggregate.cs +++ b/Netina.Domain/Entities/ProductCategories/ProductCategory.Aggregate.cs @@ -19,8 +19,16 @@ public partial class ProductCategory Files.Add(file); return file; } + + public void AddMetaTag(string key, string value) + => MetaTags.Add(ProductCategoryMetaTag.Create(key, value, Id)); } +public partial class ProductCategoryMetaTag +{ + public static ProductCategoryMetaTag Create(string key, string value, Guid productCategoryId) + => new ProductCategoryMetaTag(key, value, productCategoryId); +} public partial class ProductCategoryStorageFile { public static ProductCategoryStorageFile Create(string name, string fileLocation, string fileName, bool isHeader, bool isPrimary, StorageFileType fileType, Guid categoryId) diff --git a/Netina.Domain/Entities/ProductCategories/ProductCategory.cs b/Netina.Domain/Entities/ProductCategories/ProductCategory.cs index 788ca4c..e0690ab 100644 --- a/Netina.Domain/Entities/ProductCategories/ProductCategory.cs +++ b/Netina.Domain/Entities/ProductCategories/ProductCategory.cs @@ -27,6 +27,7 @@ public partial class ProductCategory : ApiEntity public ProductCategory? Parent { get; internal set; } //public List Children { get; internal set; } = new(); + public List MetaTags { get; internal set; } = new(); public List Products { get; internal set; } = new(); public List Files { get; internal set; } = new(); } \ No newline at end of file diff --git a/Netina.Domain/Entities/ProductCategories/ProductCategoryMetaTag.cs b/Netina.Domain/Entities/ProductCategories/ProductCategoryMetaTag.cs new file mode 100644 index 0000000..323c5e9 --- /dev/null +++ b/Netina.Domain/Entities/ProductCategories/ProductCategoryMetaTag.cs @@ -0,0 +1,16 @@ +namespace Netina.Domain.Entities.ProductCategories; + +public partial class ProductCategoryMetaTag : MetaTag +{ + public ProductCategoryMetaTag() + { + + } + public ProductCategoryMetaTag(string type, string value, Guid productCategoryId) : base(type, value) + { + ProductCategoryId = productCategoryId; + } + + public Guid ProductCategoryId { get; set; } + public ProductCategory? ProductCategory { get; set; } +} \ No newline at end of file diff --git a/Netina.Domain/Entities/Seo/MetaTag.cs b/Netina.Domain/Entities/Seo/MetaTag.cs new file mode 100644 index 0000000..ccaab62 --- /dev/null +++ b/Netina.Domain/Entities/Seo/MetaTag.cs @@ -0,0 +1,27 @@ +namespace Netina.Domain.Entities.Seo; + +[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] +public partial class MetaTag : ApiEntity +{ + public MetaTag() + { + + } + public MetaTag(string type, string value) + { + Type = type; + Value = value; + } + + public string Type { get; internal set; } = string.Empty; + public string Value { get; internal set; } = string.Empty; +} + +public partial class MetaTag +{ + public static MetaTag Create(string type, string value) + => new(type, value); +} \ No newline at end of file diff --git a/Netina.Domain/Mappers/MetaTagMapper.g.cs b/Netina.Domain/Mappers/MetaTagMapper.g.cs new file mode 100644 index 0000000..8417364 --- /dev/null +++ b/Netina.Domain/Mappers/MetaTagMapper.g.cs @@ -0,0 +1,68 @@ +using System; +using System.Linq.Expressions; +using Netina.Domain.Dtos.SmallDtos; +using Netina.Domain.Entities.Seo; + +namespace Netina.Domain.Mappers +{ + public static partial class MetaTagMapper + { + public static MetaTag AdaptToMetaTag(this MetaTagSDto p1) + { + return p1 == null ? null : new MetaTag() + { + Type = p1.Type, + Value = p1.Value, + Id = p1.Id, + CreatedAt = p1.CreatedAt + }; + } + public static MetaTag AdaptTo(this MetaTagSDto p2, MetaTag p3) + { + if (p2 == null) + { + return null; + } + MetaTag result = p3 ?? new MetaTag(); + + result.Type = p2.Type; + result.Value = p2.Value; + result.Id = p2.Id; + result.CreatedAt = p2.CreatedAt; + return result; + + } + public static MetaTagSDto AdaptToSDto(this MetaTag p4) + { + return p4 == null ? null : new MetaTagSDto() + { + Type = p4.Type, + Value = p4.Value, + Id = p4.Id, + CreatedAt = p4.CreatedAt + }; + } + public static MetaTagSDto AdaptTo(this MetaTag p5, MetaTagSDto p6) + { + if (p5 == null) + { + return null; + } + MetaTagSDto result = p6 ?? new MetaTagSDto(); + + result.Type = p5.Type; + result.Value = p5.Value; + result.Id = p5.Id; + result.CreatedAt = p5.CreatedAt; + return result; + + } + public static Expression> ProjectToSDto => p7 => new MetaTagSDto() + { + Type = p7.Type, + Value = p7.Value, + Id = p7.Id, + CreatedAt = p7.CreatedAt + }; + } +} \ No newline at end of file diff --git a/Netina.Domain/Mappers/ProductCategoryMapper.g.cs b/Netina.Domain/Mappers/ProductCategoryMapper.g.cs index fd53984..fe8e201 100644 --- a/Netina.Domain/Mappers/ProductCategoryMapper.g.cs +++ b/Netina.Domain/Mappers/ProductCategoryMapper.g.cs @@ -25,212 +25,257 @@ namespace Netina.Domain.Mappers Name = p1.ParentName, Id = p1.ParentId }, - Files = funcMain1(p1.Files), + MetaTags = funcMain1(p1.MetaTags), + Files = funcMain2(p1.Files), Id = p1.Id, CreatedAt = p1.CreatedAt }; } - public static ProductCategory AdaptTo(this ProductCategoryLDto p3, ProductCategory p4) + public static ProductCategory AdaptTo(this ProductCategoryLDto p4, ProductCategory p5) { - if (p3 == null) + if (p4 == null) { return null; } - ProductCategory result = p4 ?? new ProductCategory(); + ProductCategory result = p5 ?? new ProductCategory(); - result.Name = p3.Name; - result.Slug = p3.Slug; - result.Description = p3.Description; - result.IsMain = p3.IsMain; - result.ParentId = (Guid?)p3.ParentId; - result.Parent = funcMain2(new Never(), result.Parent, p3); - result.Files = funcMain3(p3.Files, result.Files); - result.Id = p3.Id; - result.CreatedAt = p3.CreatedAt; + result.Name = p4.Name; + result.Slug = p4.Slug; + result.Description = p4.Description; + result.IsMain = p4.IsMain; + result.ParentId = (Guid?)p4.ParentId; + result.Parent = funcMain3(new Never(), result.Parent, p4); + result.MetaTags = funcMain4(p4.MetaTags, result.MetaTags); + result.Files = funcMain5(p4.Files, result.Files); + result.Id = p4.Id; + result.CreatedAt = p4.CreatedAt; return result; } - public static Expression> ProjectToProductCategory => p9 => new ProductCategory() + public static Expression> ProjectToProductCategory => p12 => new ProductCategory() { - Name = p9.Name, - Slug = p9.Slug, - Description = p9.Description, - IsMain = p9.IsMain, - ParentId = (Guid?)p9.ParentId, + Name = p12.Name, + Slug = p12.Slug, + Description = p12.Description, + IsMain = p12.IsMain, + ParentId = (Guid?)p12.ParentId, Parent = new ProductCategory() { - Name = p9.ParentName, - Id = p9.ParentId + Name = p12.ParentName, + Id = p12.ParentId }, - Files = p9.Files.Select(p10 => new ProductCategoryStorageFile() + MetaTags = p12.MetaTags.Select(p13 => new ProductCategoryMetaTag() { - Name = p10.Name, - FileLocation = p10.FileLocation, - FileName = p10.FileName, - IsHeader = p10.IsHeader, - IsPrimary = p10.IsPrimary, - FileType = p10.FileType, - Id = p10.Id, - CreatedAt = p10.CreatedAt + Type = p13.Type, + Value = p13.Value, + Id = p13.Id, + CreatedAt = p13.CreatedAt + }).ToList(), + Files = p12.Files.Select(p14 => new ProductCategoryStorageFile() + { + Name = p14.Name, + FileLocation = p14.FileLocation, + FileName = p14.FileName, + IsHeader = p14.IsHeader, + IsPrimary = p14.IsPrimary, + FileType = p14.FileType, + Id = p14.Id, + CreatedAt = p14.CreatedAt }).ToList(), - Id = p9.Id, - CreatedAt = p9.CreatedAt + Id = p12.Id, + CreatedAt = p12.CreatedAt }; - public static ProductCategoryLDto AdaptToLDto(this ProductCategory p11) + public static ProductCategoryLDto AdaptToLDto(this ProductCategory p15) { - return p11 == null ? null : new ProductCategoryLDto() + return p15 == null ? null : new ProductCategoryLDto() { - Name = p11.Name, - Description = p11.Description, - ParentId = p11.ParentId == null ? default(Guid) : (Guid)p11.ParentId, - ParentName = p11.Parent != null ? p11.Parent.Name : string.Empty, - Slug = p11.Slug, - IsMain = p11.IsMain, - Files = funcMain4(p11.Files), - Id = p11.Id, - CreatedAt = p11.CreatedAt + Name = p15.Name, + Description = p15.Description, + ParentId = p15.ParentId == null ? default(Guid) : (Guid)p15.ParentId, + ParentName = p15.Parent != null ? p15.Parent.Name : string.Empty, + Slug = p15.Slug, + IsMain = p15.IsMain, + Files = funcMain6(p15.Files), + MetaTags = funcMain7(p15.MetaTags), + Id = p15.Id, + CreatedAt = p15.CreatedAt }; } - public static ProductCategoryLDto AdaptTo(this ProductCategory p13, ProductCategoryLDto p14) + public static ProductCategoryLDto AdaptTo(this ProductCategory p18, ProductCategoryLDto p19) { - if (p13 == null) + if (p18 == null) { return null; } - ProductCategoryLDto result = p14 ?? new ProductCategoryLDto(); + ProductCategoryLDto result = p19 ?? new ProductCategoryLDto(); - result.Name = p13.Name; - result.Description = p13.Description; - result.ParentId = p13.ParentId == null ? default(Guid) : (Guid)p13.ParentId; - result.ParentName = p13.Parent != null ? p13.Parent.Name : string.Empty; - result.Slug = p13.Slug; - result.IsMain = p13.IsMain; - result.Files = funcMain5(p13.Files, result.Files); - result.Id = p13.Id; - result.CreatedAt = p13.CreatedAt; + result.Name = p18.Name; + result.Description = p18.Description; + result.ParentId = p18.ParentId == null ? default(Guid) : (Guid)p18.ParentId; + result.ParentName = p18.Parent != null ? p18.Parent.Name : string.Empty; + result.Slug = p18.Slug; + result.IsMain = p18.IsMain; + result.Files = funcMain8(p18.Files, result.Files); + result.MetaTags = funcMain9(p18.MetaTags, result.MetaTags); + result.Id = p18.Id; + result.CreatedAt = p18.CreatedAt; return result; } - public static Expression> ProjectToLDto => p17 => new ProductCategoryLDto() + public static Expression> ProjectToLDto => p24 => new ProductCategoryLDto() { - Name = p17.Name, - Description = p17.Description, - ParentId = p17.ParentId == null ? default(Guid) : (Guid)p17.ParentId, - ParentName = p17.Parent != null ? p17.Parent.Name : string.Empty, - Slug = p17.Slug, - IsMain = p17.IsMain, - Files = p17.Files.Select(p18 => new StorageFileSDto() + Name = p24.Name, + Description = p24.Description, + ParentId = p24.ParentId == null ? default(Guid) : (Guid)p24.ParentId, + ParentName = p24.Parent != null ? p24.Parent.Name : string.Empty, + Slug = p24.Slug, + IsMain = p24.IsMain, + Files = p24.Files.Select(p25 => new StorageFileSDto() { - Name = p18.Name, - FileLocation = p18.FileLocation, - FileName = p18.FileName, - IsHeader = p18.IsHeader, - IsPrimary = p18.IsPrimary, - FileType = p18.FileType, - Id = p18.Id + Name = p25.Name, + FileLocation = p25.FileLocation, + FileName = p25.FileName, + IsHeader = p25.IsHeader, + IsPrimary = p25.IsPrimary, + FileType = p25.FileType, + Id = p25.Id }).ToList(), - Id = p17.Id, - CreatedAt = p17.CreatedAt - }; - public static ProductCategory AdaptToProductCategory(this ProductCategorySDto p19) - { - return p19 == null ? null : new ProductCategory() + MetaTags = p24.MetaTags.Select(p26 => new MetaTagSDto() { - Name = p19.Name, - Slug = p19.Slug, - Description = p19.Description, - IsMain = p19.IsMain, - ParentId = (Guid?)p19.ParentId, + Type = p26.Type, + Value = p26.Value, + Id = p26.Id, + CreatedAt = p26.CreatedAt + }).ToList(), + Id = p24.Id, + CreatedAt = p24.CreatedAt + }; + public static ProductCategory AdaptToProductCategory(this ProductCategorySDto p27) + { + return p27 == null ? null : new ProductCategory() + { + Name = p27.Name, + Slug = p27.Slug, + Description = p27.Description, + IsMain = p27.IsMain, + ParentId = (Guid?)p27.ParentId, Parent = new ProductCategory() { - Name = p19.ParentName, - Id = p19.ParentId + Name = p27.ParentName, + Id = p27.ParentId }, - Id = p19.Id, - CreatedAt = p19.CreatedAt + Id = p27.Id, + CreatedAt = p27.CreatedAt }; } - public static ProductCategory AdaptTo(this ProductCategorySDto p20, ProductCategory p21) + public static ProductCategory AdaptTo(this ProductCategorySDto p28, ProductCategory p29) { - if (p20 == null) + if (p28 == null) { return null; } - ProductCategory result = p21 ?? new ProductCategory(); + ProductCategory result = p29 ?? new ProductCategory(); - result.Name = p20.Name; - result.Slug = p20.Slug; - result.Description = p20.Description; - result.IsMain = p20.IsMain; - result.ParentId = (Guid?)p20.ParentId; - result.Parent = funcMain6(new Never(), result.Parent, p20); - result.Id = p20.Id; - result.CreatedAt = p20.CreatedAt; + result.Name = p28.Name; + result.Slug = p28.Slug; + result.Description = p28.Description; + result.IsMain = p28.IsMain; + result.ParentId = (Guid?)p28.ParentId; + result.Parent = funcMain10(new Never(), result.Parent, p28); + result.Id = p28.Id; + result.CreatedAt = p28.CreatedAt; return result; } - public static ProductCategorySDto AdaptToSDto(this ProductCategory p24) + public static ProductCategorySDto AdaptToSDto(this ProductCategory p32) { - return p24 == null ? null : new ProductCategorySDto() + return p32 == null ? null : new ProductCategorySDto() { - Name = p24.Name, - Description = p24.Description, - Slug = p24.Slug, - IsMain = p24.IsMain, - ParentId = p24.ParentId == null ? default(Guid) : (Guid)p24.ParentId, - ParentName = p24.Parent != null ? p24.Parent.Name : string.Empty, - MainImage = p24.Files.FirstOrDefault(funcMain7) != null ? p24.Files.FirstOrDefault(funcMain8).FileLocation : (p24.Files.Count > 0 ? p24.Files.FirstOrDefault().FileLocation : string.Empty), - Id = p24.Id, - CreatedAt = p24.CreatedAt + Name = p32.Name, + Description = p32.Description, + Slug = p32.Slug, + IsMain = p32.IsMain, + ParentId = p32.ParentId == null ? default(Guid) : (Guid)p32.ParentId, + ParentName = p32.Parent != null ? p32.Parent.Name : string.Empty, + MainImage = p32.Files.FirstOrDefault(funcMain11) != null ? p32.Files.FirstOrDefault(funcMain12).FileLocation : (p32.Files.Count > 0 ? p32.Files.FirstOrDefault().FileLocation : string.Empty), + Id = p32.Id, + CreatedAt = p32.CreatedAt }; } - public static ProductCategorySDto AdaptTo(this ProductCategory p25, ProductCategorySDto p26) + public static ProductCategorySDto AdaptTo(this ProductCategory p33, ProductCategorySDto p34) { - if (p25 == null) + if (p33 == null) { return null; } - ProductCategorySDto result = p26 ?? new ProductCategorySDto(); + ProductCategorySDto result = p34 ?? new ProductCategorySDto(); - result.Name = p25.Name; - result.Description = p25.Description; - result.Slug = p25.Slug; - result.IsMain = p25.IsMain; - result.ParentId = p25.ParentId == null ? default(Guid) : (Guid)p25.ParentId; - result.ParentName = p25.Parent != null ? p25.Parent.Name : string.Empty; - result.MainImage = p25.Files.FirstOrDefault(funcMain7) != null ? p25.Files.FirstOrDefault(funcMain8).FileLocation : (p25.Files.Count > 0 ? p25.Files.FirstOrDefault().FileLocation : string.Empty); - result.Id = p25.Id; - result.CreatedAt = p25.CreatedAt; + result.Name = p33.Name; + result.Description = p33.Description; + result.Slug = p33.Slug; + result.IsMain = p33.IsMain; + result.ParentId = p33.ParentId == null ? default(Guid) : (Guid)p33.ParentId; + result.ParentName = p33.Parent != null ? p33.Parent.Name : string.Empty; + result.MainImage = p33.Files.FirstOrDefault(funcMain11) != null ? p33.Files.FirstOrDefault(funcMain12).FileLocation : (p33.Files.Count > 0 ? p33.Files.FirstOrDefault().FileLocation : string.Empty); + result.Id = p33.Id; + result.CreatedAt = p33.CreatedAt; return result; } - public static Expression> ProjectToSDto => p27 => new ProductCategorySDto() + public static Expression> ProjectToSDto => p35 => new ProductCategorySDto() { - Name = p27.Name, - Description = p27.Description, - Slug = p27.Slug, - IsMain = p27.IsMain, - ParentId = p27.ParentId == null ? default(Guid) : (Guid)p27.ParentId, - ParentName = p27.Parent != null ? p27.Parent.Name : string.Empty, - MainImage = p27.Files.FirstOrDefault(f => f.IsPrimary) != null ? p27.Files.FirstOrDefault(f => f.IsPrimary).FileLocation : (p27.Files.Count > 0 ? p27.Files.FirstOrDefault().FileLocation : string.Empty), - Id = p27.Id, - CreatedAt = p27.CreatedAt + Name = p35.Name, + Description = p35.Description, + Slug = p35.Slug, + IsMain = p35.IsMain, + ParentId = p35.ParentId == null ? default(Guid) : (Guid)p35.ParentId, + ParentName = p35.Parent != null ? p35.Parent.Name : string.Empty, + MainImage = p35.Files.FirstOrDefault(f => f.IsPrimary) != null ? p35.Files.FirstOrDefault(f => f.IsPrimary).FileLocation : (p35.Files.Count > 0 ? p35.Files.FirstOrDefault().FileLocation : string.Empty), + Id = p35.Id, + CreatedAt = p35.CreatedAt }; - private static List funcMain1(List p2) + private static List funcMain1(List p2) { if (p2 == null) { return null; } - List result = new List(p2.Count); + List result = new List(p2.Count); int i = 0; int len = p2.Count; while (i < len) { - StorageFileSDto item = p2[i]; + MetaTagSDto item = p2[i]; + result.Add(item == null ? null : new ProductCategoryMetaTag() + { + Type = item.Type, + Value = item.Value, + Id = item.Id, + CreatedAt = item.CreatedAt + }); + i++; + } + return result; + + } + + private static List funcMain2(List p3) + { + if (p3 == null) + { + return null; + } + List result = new List(p3.Count); + + int i = 0; + int len = p3.Count; + + while (i < len) + { + StorageFileSDto item = p3[i]; result.Add(item == null ? null : new ProductCategoryStorageFile() { Name = item.Name, @@ -248,30 +293,57 @@ namespace Netina.Domain.Mappers } - private static ProductCategory funcMain2(Never p5, ProductCategory p6, ProductCategoryLDto p3) + private static ProductCategory funcMain3(Never p6, ProductCategory p7, ProductCategoryLDto p4) { - ProductCategory result = p6 ?? new ProductCategory(); + ProductCategory result = p7 ?? new ProductCategory(); - result.Name = p3.ParentName; - result.Id = p3.ParentId; + result.Name = p4.ParentName; + result.Id = p4.ParentId; return result; } - private static List funcMain3(List p7, List p8) + private static List funcMain4(List p8, List p9) { - if (p7 == null) + if (p8 == null) { return null; } - List result = new List(p7.Count); + List result = new List(p8.Count); int i = 0; - int len = p7.Count; + int len = p8.Count; while (i < len) { - StorageFileSDto item = p7[i]; + MetaTagSDto item = p8[i]; + result.Add(item == null ? null : new ProductCategoryMetaTag() + { + Type = item.Type, + Value = item.Value, + Id = item.Id, + CreatedAt = item.CreatedAt + }); + i++; + } + return result; + + } + + private static List funcMain5(List p10, List p11) + { + if (p10 == null) + { + return null; + } + List result = new List(p10.Count); + + int i = 0; + int len = p10.Count; + + while (i < len) + { + StorageFileSDto item = p10[i]; result.Add(item == null ? null : new ProductCategoryStorageFile() { Name = item.Name, @@ -289,20 +361,20 @@ namespace Netina.Domain.Mappers } - private static List funcMain4(List p12) + private static List funcMain6(List p16) { - if (p12 == null) + if (p16 == null) { return null; } - List result = new List(p12.Count); + List result = new List(p16.Count); int i = 0; - int len = p12.Count; + int len = p16.Count; while (i < len) { - ProductCategoryStorageFile item = p12[i]; + ProductCategoryStorageFile item = p16[i]; result.Add(item == null ? null : new StorageFileSDto() { Name = item.Name, @@ -319,20 +391,47 @@ namespace Netina.Domain.Mappers } - private static List funcMain5(List p15, List p16) + private static List funcMain7(List p17) { - if (p15 == null) + if (p17 == null) { return null; } - List result = new List(p15.Count); + List result = new List(p17.Count); int i = 0; - int len = p15.Count; + int len = p17.Count; while (i < len) { - ProductCategoryStorageFile item = p15[i]; + ProductCategoryMetaTag item = p17[i]; + result.Add(item == null ? null : new MetaTagSDto() + { + Type = item.Type, + Value = item.Value, + Id = item.Id, + CreatedAt = item.CreatedAt + }); + i++; + } + return result; + + } + + private static List funcMain8(List p20, List p21) + { + if (p20 == null) + { + return null; + } + List result = new List(p20.Count); + + int i = 0; + int len = p20.Count; + + while (i < len) + { + ProductCategoryStorageFile item = p20[i]; result.Add(item == null ? null : new StorageFileSDto() { Name = item.Name, @@ -349,22 +448,49 @@ namespace Netina.Domain.Mappers } - private static ProductCategory funcMain6(Never p22, ProductCategory p23, ProductCategorySDto p20) + private static List funcMain9(List p22, List p23) { - ProductCategory result = p23 ?? new ProductCategory(); + if (p22 == null) + { + return null; + } + List result = new List(p22.Count); - result.Name = p20.ParentName; - result.Id = p20.ParentId; + int i = 0; + int len = p22.Count; + + while (i < len) + { + ProductCategoryMetaTag item = p22[i]; + result.Add(item == null ? null : new MetaTagSDto() + { + Type = item.Type, + Value = item.Value, + Id = item.Id, + CreatedAt = item.CreatedAt + }); + i++; + } return result; } - private static bool funcMain7(ProductCategoryStorageFile f) + private static ProductCategory funcMain10(Never p30, ProductCategory p31, ProductCategorySDto p28) + { + ProductCategory result = p31 ?? new ProductCategory(); + + result.Name = p28.ParentName; + result.Id = p28.ParentId; + return result; + + } + + private static bool funcMain11(ProductCategoryStorageFile f) { return f.IsPrimary; } - private static bool funcMain8(ProductCategoryStorageFile f) + private static bool funcMain12(ProductCategoryStorageFile f) { return f.IsPrimary; } diff --git a/Netina.Domain/Mappers/ProductCategoryMetaTagMapper.g.cs b/Netina.Domain/Mappers/ProductCategoryMetaTagMapper.g.cs new file mode 100644 index 0000000..27e80ae --- /dev/null +++ b/Netina.Domain/Mappers/ProductCategoryMetaTagMapper.g.cs @@ -0,0 +1,6 @@ +namespace Netina.Domain.Mappers +{ + public static partial class ProductCategoryMetaTagMapper + { + } +} \ No newline at end of file diff --git a/Netina.Domain/Netina.Domain.csproj b/Netina.Domain/Netina.Domain.csproj index 0ae6bde..e8f885c 100644 --- a/Netina.Domain/Netina.Domain.csproj +++ b/Netina.Domain/Netina.Domain.csproj @@ -1,6 +1,6 @@  - + - + @@ -76,6 +76,7 @@ + diff --git a/Netina.Repository/Handlers/Customers/GetCustomersQueryHandler.cs b/Netina.Repository/Handlers/Customers/GetCustomersQueryHandler.cs new file mode 100644 index 0000000..a13c00b --- /dev/null +++ b/Netina.Repository/Handlers/Customers/GetCustomersQueryHandler.cs @@ -0,0 +1,16 @@ +namespace Netina.Repository.Handlers.Customers; + +public class GetCustomersQueryHandler(IRepositoryWrapper repositoryWrapper) : IRequestHandler> +{ + public async Task> Handle(GetCustomersQuery request, CancellationToken cancellationToken) + { + var response = await repositoryWrapper.SetRepository() + .TableNoTracking + .Skip(request.Page * request.Count) + .Take(request.Page) + .Select(CustomerMapper.ProjectToSDto) + .ToListAsync(cancellationToken); + + return response; + } +} \ No newline at end of file diff --git a/Netina.Repository/Handlers/ProductCategories/CreateProductCategoryCommandHandler.cs b/Netina.Repository/Handlers/ProductCategories/CreateProductCategoryCommandHandler.cs index 4ceef7c..a56151a 100644 --- a/Netina.Repository/Handlers/ProductCategories/CreateProductCategoryCommandHandler.cs +++ b/Netina.Repository/Handlers/ProductCategories/CreateProductCategoryCommandHandler.cs @@ -9,9 +9,11 @@ public class CreateProductCategoryCommandHandler(IRepositoryWrapper repositoryWr if (request.ParentId != default) ent.SetParent(request.ParentId); foreach (var file in request.Files) - { ent.AddFile(file.Name, file.FileLocation, file.FileName, file.IsHeader, file.IsPrimary, file.FileType); - } + + foreach (var (key, value) in request.MetaTags) + ent.AddMetaTag(key, value); + repositoryWrapper.SetRepository().Add(ent); await repositoryWrapper.SaveChangesAsync(cancellationToken); await UpdateFaqAsync(ent, request.Faqs, cancellationToken); diff --git a/Netina.Repository/Handlers/ProductCategories/UpdateProductCategoryCommandHandler.cs b/Netina.Repository/Handlers/ProductCategories/UpdateProductCategoryCommandHandler.cs index cb7be47..7b11886 100644 --- a/Netina.Repository/Handlers/ProductCategories/UpdateProductCategoryCommandHandler.cs +++ b/Netina.Repository/Handlers/ProductCategories/UpdateProductCategoryCommandHandler.cs @@ -32,6 +32,20 @@ public class UpdateProductCategoryCommandHandler(IRepositoryWrapper repositoryWr { newEnt.AddFile(file.Name, file.FileLocation, file.FileName, file.IsHeader, file.IsPrimary, file.FileType); } + + var dbMetaTags = await repositoryWrapper.SetRepository() + .TableNoTracking + .Where(f => f.ProductCategoryId == ent.Id) + .ToListAsync(cancellationToken); + foreach (var feature in dbMetaTags.Where(feature => request.MetaTags.Any(f => f.Key == feature.Type) == false)) + { + repositoryWrapper.SetRepository() + .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); + repositoryWrapper.SetRepository().Update(newEnt); await repositoryWrapper.SaveChangesAsync(cancellationToken); await UpdateFaqAsync(newEnt, request.Faqs, cancellationToken); diff --git a/Netina.Repository/Handlers/Products/GetProductsQueryHandler.cs b/Netina.Repository/Handlers/Products/GetProductsQueryHandler.cs index aeb420c..9112ca3 100644 --- a/Netina.Repository/Handlers/Products/GetProductsQueryHandler.cs +++ b/Netina.Repository/Handlers/Products/GetProductsQueryHandler.cs @@ -13,7 +13,7 @@ public class GetProductsQueryHandler( if (currentUserService.JwtToken == null) products = products.Where(p => p.BeDisplayed); var roleClaim = currentUserService.JwtToken?.Claims.FirstOrDefault(c => c.Type == "role"); - if (roleClaim != null && roleClaim.Value.Contains("Customer")) + if (roleClaim != null && roleClaim.Value.Contains("Customer")) products = products.Where(p => p.BeDisplayed); if (request.IsActive != null) @@ -39,6 +39,7 @@ public class GetProductsQueryHandler( { var cats = await mediator.Send(new GetProductCategoryChildrenQuery(request.CategoryId), cancellationToken); products = products.Where(p => cats.Contains(p.CategoryId)); + response.Seo = await GetSeoResponse(request.CategoryId, cancellationToken); } if (request.BrandIds is { Length: > 0 }) products = products.Where(p => request.BrandIds.Contains(p.BrandId)); @@ -46,7 +47,7 @@ public class GetProductsQueryHandler( products = products.Where(p => p.Cost >= request.MinPrice); if (request.MaxPrice > 0) products = products.Where(p => p.Cost <= request.MaxPrice); - + if (request.SpecialOffer != null) { @@ -90,4 +91,29 @@ public class GetProductsQueryHandler( return response; } + private async Task GetSeoResponse(Guid categoryId, CancellationToken cancellationToken = default) + { + var response = new SeoResponseDto(); + var metaTags = await repositoryWrapper.SetRepository().TableNoTracking + .Where(c => c.ProductCategoryId == categoryId) + .ToListAsync(cancellationToken); + var titleMeta = metaTags.FirstOrDefault(m => m.Type.ToLower().Contains("title")); + if (titleMeta != null) + { + response.Title = titleMeta.Value; + metaTags.Remove(titleMeta); + } + + var descriptionMeta = metaTags.FirstOrDefault(m => m.Type.ToLower().Contains("description")); + if (descriptionMeta != null) + { + response.Description = descriptionMeta.Value; + metaTags.Remove(descriptionMeta); + } + + foreach (var metaTag in metaTags) + response.MetaTags.Add(metaTag.Type, metaTag.Value); + return response; + } + } \ No newline at end of file diff --git a/Netina.Repository/Migrations/20241025105822_addMetaTag.Designer.cs b/Netina.Repository/Migrations/20241025105822_addMetaTag.Designer.cs new file mode 100644 index 0000000..cef3130 --- /dev/null +++ b/Netina.Repository/Migrations/20241025105822_addMetaTag.Designer.cs @@ -0,0 +1,2195 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Netina.Repository.Models; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace NetinaShop.Repository.Migrations +{ + [DbContext(typeof(ApplicationContext))] + [Migration("20241025105822_addMetaTag")] + partial class addMetaTag + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("public") + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "fuzzystrmatch"); + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "pg_trgm"); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaims", "public"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Claims", "public"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("Logins", "public"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "public"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("Tokens", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Accounting.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("double precision"); + + b.Property("Authority") + .IsRequired() + .HasColumnType("text"); + + b.Property("CardPan") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("CustomerId") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("FactorNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("OrderId") + .HasColumnType("uuid"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TransactionCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.Blog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.Property("Content") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("IsSuggested") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReadingTime") + .HasColumnType("integer"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.Property("Summery") + .IsRequired() + .HasColumnType("text"); + + b.Property("Tags") + .IsRequired() + .HasColumnType("text"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.HasIndex("CategoryId"); + + b.ToTable("Blogs", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsMain") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("BlogCategories", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Brands.Brand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("EnglishName") + .IsRequired() + .HasColumnType("text"); + + b.Property("HasSpecialPage") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("PageUrl") + .IsRequired() + .HasColumnType("text"); + + b.Property("PersianName") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Brands", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Comments.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Content") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("character varying(21)"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("IsConfirmed") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("IsRoot") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("Rate") + .HasColumnType("real"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("UserId"); + + b.ToTable("Comments", "public"); + + b.HasDiscriminator().HasValue("Comment"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Discounts.Discount", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AmountType") + .HasColumnType("integer"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("Count") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("DiscountAmount") + .HasColumnType("bigint"); + + b.Property("DiscountPercent") + .HasColumnType("integer"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("character varying(21)"); + + b.Property("ExpireDate") + .HasColumnType("timestamp without time zone"); + + b.Property("HasCode") + .HasColumnType("boolean"); + + b.Property("HasPriceCeiling") + .HasColumnType("boolean"); + + b.Property("HasPriceFloor") + .HasColumnType("boolean"); + + b.Property("Immortal") + .HasColumnType("boolean"); + + b.Property("IsForFirstPurchase") + .HasColumnType("boolean"); + + b.Property("IsForInvitation") + .HasColumnType("boolean"); + + b.Property("IsForSaleCooperation") + .HasColumnType("boolean"); + + b.Property("IsInfinity") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("IsSpecialOffer") + .HasColumnType("boolean"); + + b.Property("MarketerId") + .HasColumnType("uuid"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("PriceCeiling") + .HasColumnType("bigint"); + + b.Property("PriceFloor") + .HasColumnType("bigint"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("StartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("UseCount") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("MarketerId") + .IsUnique(); + + b.ToTable("Discounts", "public"); + + b.HasDiscriminator().HasValue("Discount"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Orders.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("CustomerId") + .HasColumnType("uuid"); + + b.Property("DeliveredAt") + .HasColumnType("timestamp without time zone"); + + b.Property("DeliveryPrice") + .HasColumnType("double precision"); + + b.Property("DiscountCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("DiscountCodePrice") + .HasColumnType("double precision"); + + b.Property("DiscountId") + .HasColumnType("uuid"); + + b.Property("DiscountPrice") + .HasColumnType("double precision"); + + b.Property("DoneAt") + .HasColumnType("timestamp without time zone"); + + b.Property("FactorCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsPayed") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("OrderAt") + .HasColumnType("timestamp without time zone"); + + b.Property("OrderStatus") + .HasColumnType("integer"); + + b.Property("PackingPrice") + .HasColumnType("double precision"); + + b.Property("PayedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("PaymentMethod") + .HasColumnType("integer"); + + b.Property("PreparingMinute") + .HasColumnType("integer"); + + b.Property("ProductDiscountPrice") + .HasColumnType("double precision"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("ServicePrice") + .HasColumnType("double precision"); + + b.Property("TaxesPrice") + .HasColumnType("double precision"); + + b.Property("TotalPrice") + .HasColumnType("double precision"); + + b.Property("TotalProductsPrice") + .HasColumnType("double precision"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("DiscountId"); + + b.ToTable("Orders", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Orders.OrderDelivery", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddressId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("DeliveryCost") + .HasColumnType("double precision"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("OrderId") + .HasColumnType("uuid"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("ShippingId") + .HasColumnType("uuid"); + + b.Property("TrackingCode") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AddressId"); + + b.HasIndex("OrderId") + .IsUnique(); + + b.HasIndex("ShippingId"); + + b.ToTable("OrderDeliveries", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Orders.OrderProduct", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Count") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("HasDiscount") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("OrderId") + .HasColumnType("uuid"); + + b.Property("OrderProductStatus") + .HasColumnType("integer"); + + b.Property("PackingCost") + .HasColumnType("double precision"); + + b.Property("PackingFee") + .HasColumnType("double precision"); + + b.Property("ProductCategoryId") + .HasColumnType("uuid"); + + b.Property("ProductCost") + .HasColumnType("double precision"); + + b.Property("ProductFee") + .HasColumnType("double precision"); + + b.Property("ProductFeeWithDiscount") + .HasColumnType("double precision"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("ProductId"); + + b.ToTable("OrderProducts", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsMain") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("ProductCategories", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("BeDisplayed") + .HasColumnType("boolean"); + + b.Property("BrandId") + .HasColumnType("uuid"); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.Property("Cost") + .HasColumnType("double precision"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("EnglishName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExpertCheck") + .IsRequired() + .HasColumnType("text"); + + b.Property("HasExpressDelivery") + .HasColumnType("boolean"); + + b.Property("IsEnable") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("MaxOrderCount") + .HasColumnType("integer"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("PackingCost") + .HasColumnType("double precision"); + + b.Property("PersianName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Rate") + .HasColumnType("real"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReviewCount") + .HasColumnType("integer"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.Property("Stock") + .HasColumnType("integer"); + + b.Property("Summery") + .IsRequired() + .HasColumnType("text"); + + b.Property("Tags") + .IsRequired() + .HasColumnType("text"); + + b.Property("Viewed") + .HasColumnType("integer"); + + b.Property("Warranty") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.HasIndex("BrandId"); + + b.HasIndex("CategoryId"); + + b.ToTable("Products", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Detail") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsFeature") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("ProductId"); + + b.ToTable("Specifications", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Seo.MetaTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(34) + .HasColumnType("character varying(34)"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("MetaTags", "public"); + + b.HasDiscriminator().HasValue("MetaTag"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Netina.Domain.Entities.StorageFiles.StorageFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(34) + .HasColumnType("character varying(34)"); + + b.Property("FileLocation") + .IsRequired() + .HasColumnType("text"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("text"); + + b.Property("FileType") + .HasColumnType("integer"); + + b.Property("IsHeader") + .HasColumnType("boolean"); + + b.Property("IsPrimary") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("StorageFiles", "public"); + + b.HasDiscriminator().HasValue("StorageFile"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.ApplicationRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("EnglishName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PersianName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("Roles", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.ApplicationUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("BirthDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Gender") + .HasColumnType("integer"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NationalId") + .IsRequired() + .HasColumnType("text"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("SignUpStatus") + .HasColumnType("integer"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("Users", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Customers", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.Manager", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("LatestVersionUsed") + .HasColumnType("double precision"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Managers", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.Marketer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("FatherName") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("LastSettlement") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Shaba") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Marketers", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.NewsletterMember", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("NewsletterMembers", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.UserAddress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Address") + .IsRequired() + .HasColumnType("text"); + + b.Property("BuildingUnit") + .IsRequired() + .HasColumnType("text"); + + b.Property("City") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("LocationLat") + .HasColumnType("real"); + + b.Property("LocationLong") + .HasColumnType("real"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Plaque") + .IsRequired() + .HasColumnType("text"); + + b.Property("PostalCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Province") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReceiverFullName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReceiverPhoneNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserAddresses", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.UserFavoriteProduct", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("UserId"); + + b.ToTable("UserFavoriteProducts", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Warehouses.Shipping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("DeliveryCost") + .HasColumnType("double precision"); + + b.Property("IsExpressShipping") + .HasColumnType("boolean"); + + b.Property("IsOriginalWarehouse") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("IsShipBySeller") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("WarehouseName") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorkingDays") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("Shippings", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogComment", b => + { + b.HasBaseType("Netina.Domain.Entities.Comments.Comment"); + + b.Property("BlogId") + .HasColumnType("uuid"); + + b.HasIndex("BlogId"); + + b.HasDiscriminator().HasValue("BlogComment"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.ProductComment", b => + { + b.HasBaseType("Netina.Domain.Entities.Comments.Comment"); + + b.Property("IsBuyer") + .HasColumnType("boolean"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.HasIndex("ProductId"); + + b.HasDiscriminator().HasValue("ProductComment"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Discounts.CategoryDiscount", b => + { + b.HasBaseType("Netina.Domain.Entities.Discounts.Discount"); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.HasIndex("CategoryId"); + + b.HasDiscriminator().HasValue("CategoryDiscount"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Discounts.ProductDiscount", b => + { + b.HasBaseType("Netina.Domain.Entities.Discounts.Discount"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.HasIndex("ProductId"); + + b.HasDiscriminator().HasValue("ProductDiscount"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategoryMetaTag", b => + { + b.HasBaseType("Netina.Domain.Entities.Seo.MetaTag"); + + b.Property("ProductCategoryId") + .HasColumnType("uuid"); + + b.HasIndex("ProductCategoryId"); + + b.HasDiscriminator().HasValue("ProductCategoryMetaTag"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogStorageFile", b => + { + b.HasBaseType("Netina.Domain.Entities.StorageFiles.StorageFile"); + + b.Property("BlogId") + .HasColumnType("uuid"); + + b.HasIndex("BlogId"); + + b.HasDiscriminator().HasValue("BlogStorageFile"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Brands.BrandStorageFile", b => + { + b.HasBaseType("Netina.Domain.Entities.StorageFiles.StorageFile"); + + b.Property("BrandId") + .HasColumnType("uuid"); + + b.HasIndex("BrandId"); + + b.HasDiscriminator().HasValue("BrandStorageFile"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategoryStorageFile", b => + { + b.HasBaseType("Netina.Domain.Entities.StorageFiles.StorageFile"); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.HasIndex("CategoryId"); + + b.HasDiscriminator().HasValue("ProductCategoryStorageFile"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.ProductStorageFile", b => + { + b.HasBaseType("Netina.Domain.Entities.StorageFiles.StorageFile"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.HasIndex("ProductId"); + + b.HasDiscriminator().HasValue("ProductStorageFile"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Accounting.Payment", b => + { + b.HasOne("Netina.Domain.Entities.Users.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Orders.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Customer"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.Blog", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "Author") + .WithMany() + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Blogs.BlogCategory", "Category") + .WithMany("Blogs") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Author"); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogCategory", b => + { + b.HasOne("Netina.Domain.Entities.Blogs.BlogCategory", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Comments.Comment", b => + { + b.HasOne("Netina.Domain.Entities.Comments.Comment", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId"); + + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Discounts.Discount", b => + { + b.HasOne("Netina.Domain.Entities.Users.Marketer", "Marketer") + .WithOne("Discount") + .HasForeignKey("Netina.Domain.Entities.Discounts.Discount", "MarketerId"); + + b.Navigation("Marketer"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Orders.Order", b => + { + b.HasOne("Netina.Domain.Entities.Users.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Discounts.Discount", null) + .WithMany("Orders") + .HasForeignKey("DiscountId"); + + b.Navigation("Customer"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Orders.OrderDelivery", b => + { + b.HasOne("Netina.Domain.Entities.Users.UserAddress", "Address") + .WithMany() + .HasForeignKey("AddressId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Orders.Order", "Order") + .WithOne("OrderDelivery") + .HasForeignKey("Netina.Domain.Entities.Orders.OrderDelivery", "OrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Warehouses.Shipping", "Shipping") + .WithMany() + .HasForeignKey("ShippingId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Address"); + + b.Navigation("Order"); + + b.Navigation("Shipping"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Orders.OrderProduct", b => + { + b.HasOne("Netina.Domain.Entities.Orders.Order", "Order") + .WithMany("OrderProducts") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Products.Product", "Product") + .WithMany("OrderProducts") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Order"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategory", b => + { + b.HasOne("Netina.Domain.Entities.ProductCategories.ProductCategory", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.Product", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "Author") + .WithMany() + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Brands.Brand", "Brand") + .WithMany("Products") + .HasForeignKey("BrandId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.ProductCategories.ProductCategory", "Category") + .WithMany("Products") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Author"); + + b.Navigation("Brand"); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.Specification", b => + { + b.HasOne("Netina.Domain.Entities.Products.Specification", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId"); + + b.HasOne("Netina.Domain.Entities.Products.Product", "Product") + .WithMany("Specifications") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.Customer", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "User") + .WithOne("Customer") + .HasForeignKey("Netina.Domain.Entities.Users.Customer", "UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.Manager", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "User") + .WithOne("Manager") + .HasForeignKey("Netina.Domain.Entities.Users.Manager", "UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.Marketer", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "User") + .WithOne("Marketer") + .HasForeignKey("Netina.Domain.Entities.Users.Marketer", "UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.UserAddress", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "User") + .WithMany("Addresses") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.UserFavoriteProduct", b => + { + b.HasOne("Netina.Domain.Entities.Products.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Product"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogComment", b => + { + b.HasOne("Netina.Domain.Entities.Blogs.Blog", "Blog") + .WithMany() + .HasForeignKey("BlogId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Blog"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.ProductComment", b => + { + b.HasOne("Netina.Domain.Entities.Products.Product", "Product") + .WithMany("Comments") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Discounts.CategoryDiscount", b => + { + b.HasOne("Netina.Domain.Entities.ProductCategories.ProductCategory", "Category") + .WithMany() + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Discounts.ProductDiscount", b => + { + b.HasOne("Netina.Domain.Entities.Products.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategoryMetaTag", b => + { + b.HasOne("Netina.Domain.Entities.ProductCategories.ProductCategory", "ProductCategory") + .WithMany("MetaTags") + .HasForeignKey("ProductCategoryId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("ProductCategory"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogStorageFile", b => + { + b.HasOne("Netina.Domain.Entities.Blogs.Blog", "Blog") + .WithMany("Files") + .HasForeignKey("BlogId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Blog"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Brands.BrandStorageFile", b => + { + b.HasOne("Netina.Domain.Entities.Brands.Brand", "Brand") + .WithMany("Files") + .HasForeignKey("BrandId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Brand"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategoryStorageFile", b => + { + b.HasOne("Netina.Domain.Entities.ProductCategories.ProductCategory", "Category") + .WithMany("Files") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.ProductStorageFile", b => + { + b.HasOne("Netina.Domain.Entities.Products.Product", "Product") + .WithMany("Files") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.Blog", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogCategory", b => + { + b.Navigation("Blogs"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Brands.Brand", b => + { + b.Navigation("Files"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Comments.Comment", b => + { + b.Navigation("Children"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Discounts.Discount", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Orders.Order", b => + { + b.Navigation("OrderDelivery"); + + b.Navigation("OrderProducts"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategory", b => + { + b.Navigation("Files"); + + b.Navigation("MetaTags"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.Product", b => + { + b.Navigation("Comments"); + + b.Navigation("Files"); + + b.Navigation("OrderProducts"); + + b.Navigation("Specifications"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.Specification", b => + { + b.Navigation("Children"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.ApplicationUser", b => + { + b.Navigation("Addresses"); + + b.Navigation("Customer"); + + b.Navigation("Manager"); + + b.Navigation("Marketer"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.Marketer", b => + { + b.Navigation("Discount"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Netina.Repository/Migrations/20241025105822_addMetaTag.cs b/Netina.Repository/Migrations/20241025105822_addMetaTag.cs new file mode 100644 index 0000000..43235eb --- /dev/null +++ b/Netina.Repository/Migrations/20241025105822_addMetaTag.cs @@ -0,0 +1,59 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace NetinaShop.Repository.Migrations +{ + /// + public partial class addMetaTag : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "MetaTags", + schema: "public", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Type = table.Column(type: "text", nullable: false), + Value = table.Column(type: "text", nullable: false), + Discriminator = table.Column(type: "character varying(34)", maxLength: 34, nullable: false), + ProductCategoryId = table.Column(type: "uuid", nullable: true), + RemovedAt = table.Column(type: "timestamp without time zone", nullable: false), + CreatedAt = table.Column(type: "timestamp without time zone", nullable: false), + CreatedBy = table.Column(type: "text", nullable: false), + IsRemoved = table.Column(type: "boolean", nullable: false), + RemovedBy = table.Column(type: "text", nullable: false), + ModifiedAt = table.Column(type: "timestamp without time zone", nullable: false), + ModifiedBy = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_MetaTags", x => x.Id); + table.ForeignKey( + name: "FK_MetaTags_ProductCategories_ProductCategoryId", + column: x => x.ProductCategoryId, + principalSchema: "public", + principalTable: "ProductCategories", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_MetaTags_ProductCategoryId", + schema: "public", + table: "MetaTags", + column: "ProductCategoryId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "MetaTags", + schema: "public"); + } + } +} diff --git a/Netina.Repository/Migrations/ApplicationContextModelSnapshot.cs b/Netina.Repository/Migrations/ApplicationContextModelSnapshot.cs index 663ef67..ee8ceea 100644 --- a/Netina.Repository/Migrations/ApplicationContextModelSnapshot.cs +++ b/Netina.Repository/Migrations/ApplicationContextModelSnapshot.cs @@ -1032,6 +1032,58 @@ namespace NetinaShop.Repository.Migrations b.ToTable("Specifications", "public"); }); + modelBuilder.Entity("Netina.Domain.Entities.Seo.MetaTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(34) + .HasColumnType("character varying(34)"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("MetaTags", "public"); + + b.HasDiscriminator().HasValue("MetaTag"); + + b.UseTphMappingStrategy(); + }); + modelBuilder.Entity("Netina.Domain.Entities.StorageFiles.StorageFile", b => { b.Property("Id") @@ -1634,6 +1686,18 @@ namespace NetinaShop.Repository.Migrations b.HasDiscriminator().HasValue("ProductDiscount"); }); + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategoryMetaTag", b => + { + b.HasBaseType("Netina.Domain.Entities.Seo.MetaTag"); + + b.Property("ProductCategoryId") + .HasColumnType("uuid"); + + b.HasIndex("ProductCategoryId"); + + b.HasDiscriminator().HasValue("ProductCategoryMetaTag"); + }); + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogStorageFile", b => { b.HasBaseType("Netina.Domain.Entities.StorageFiles.StorageFile"); @@ -1996,6 +2060,16 @@ namespace NetinaShop.Repository.Migrations b.Navigation("Product"); }); + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategoryMetaTag", b => + { + b.HasOne("Netina.Domain.Entities.ProductCategories.ProductCategory", "ProductCategory") + .WithMany("MetaTags") + .HasForeignKey("ProductCategoryId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("ProductCategory"); + }); + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogStorageFile", b => { b.HasOne("Netina.Domain.Entities.Blogs.Blog", "Blog") @@ -2076,6 +2150,8 @@ namespace NetinaShop.Repository.Migrations { b.Navigation("Files"); + b.Navigation("MetaTags"); + b.Navigation("Products"); }); diff --git a/Netina.Repository/Netina.Repository.csproj b/Netina.Repository/Netina.Repository.csproj index 1a79e69..b32f97e 100644 --- a/Netina.Repository/Netina.Repository.csproj +++ b/Netina.Repository/Netina.Repository.csproj @@ -30,6 +30,7 @@ +