Compare commits

4 Commits

Author SHA1 Message Date
hosseinJavadi 6d35ef772c category 2026-04-22 22:37:31 +04:30
hosseinJavadi 15d11122b8 UseHiLo 2026-04-22 21:26:23 +04:30
hosseinJavadi 64ee78e320 Infrastructure 2026-04-22 20:51:02 +04:30
hosseinJavadi c64c3dd9be . 2026-04-18 22:36:21 +04:30
217 changed files with 7525 additions and 1042 deletions
@@ -0,0 +1,13 @@
using FluentValidation.Results;
namespace Vizhvizh.BuildingBlocks.Application.Exceptions;
public class CommandValidationException : Exception
{
public CommandValidationException(List<ValidationFailure> errors)
{
Errors = errors;
}
public List<ValidationFailure> Errors { get; set; }
}
@@ -0,0 +1,82 @@
using FluentValidation;
using System.ComponentModel.DataAnnotations;
using Vizhvizh.BuildingBlocks.Application.Configuration.Commnad;
using Vizhvizh.BuildingBlocks.Application.Exceptions;
using Vizhvizh.BuildingBlocks.Domain.Contract;
namespace Vizhvizh.BuildingBlocks.Application.Validations;
public class ValidationCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand>
where TCommand : ICommand
{
private readonly ICommandHandler<TCommand> _decorated;
private readonly IEnumerable<IValidator<TCommand>> _validators;
public ValidationCommandHandlerDecorator(
ICommandHandler<TCommand> decorated,
IEnumerable<IValidator<TCommand>> validators)
{
_decorated = decorated;
_validators = validators;
}
public async Task Handle(TCommand command, CancellationToken cancellationToken)
{
if (_validators.Any())
{
var context = new ValidationContext<TCommand>(command);
var validationResults = await Task.WhenAll(
_validators.Select(v => v.ValidateAsync(context, cancellationToken)));
var failures = validationResults
.SelectMany(r => r.Errors)
.Where(f => f != null)
.ToList();
if (failures.Any())
{
throw new CommandValidationException(failures);
}
}
await _decorated.Handle(command, cancellationToken);
}
}
// اگر Command شما خروجی دارد (ICommandHandler<TCommand, TResult>)
public class ValidationCommandHandlerDecorator<TCommand, TResult> : ICommandHandler<TCommand, TResult>
where TCommand : ICommand<TResult>
{
private readonly ICommandHandler<TCommand, TResult> _decorated;
private readonly IEnumerable<IValidator<TCommand>> _validators;
public ValidationCommandHandlerDecorator(
ICommandHandler<TCommand, TResult> decorated,
IEnumerable<IValidator<TCommand>> validators)
{
_decorated = decorated;
_validators = validators;
}
public async Task<TResult> Handle(TCommand command, CancellationToken cancellationToken)
{
if (_validators.Any())
{
var context = new ValidationContext<TCommand>(command);
var validationResults = await Task.WhenAll(
_validators.Select(v => v.ValidateAsync(context, cancellationToken)));
var failures = validationResults
.SelectMany(r => r.Errors)
.Where(f => f != null)
.ToList();
if (failures.Any())
{
throw new CommandValidationException(failures);
}
}
return await _decorated.Handle(command, cancellationToken);
}
}
@@ -6,6 +6,16 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation" Version="12.1.1" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.25" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.25" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.25" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Scrutor" Version="6.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VichVich.BuildingBlocks.Domain\Vizhvizh.BuildingBlocks.Domain.csproj" />
</ItemGroup>
@@ -1,6 +1,6 @@
namespace Vizhvizh.BuildingBlocks.Domain;
public class DomainEventBase : IDomainEvent
public abstract class DomainEventBase : IDomainEvent
{
public Guid Id { get; }
+2
View File
@@ -11,6 +11,8 @@ public abstract class Entity<T>
CreateOn = DateTime.Now;
}
public T Id { get; protected set; }
public byte[] RowVersion { get; private set; }
public DateTime CreateOn { get; init ; }
private List<IDomainEvent> _domainEvents;
@@ -1,10 +1,12 @@
namespace Vizhvizh.BuildingBlocks.Domain;
public interface IRepositoryBase<TDomain, TId>
where TDomain : Entity<TId> where TId : ITypeIdValueBase
public interface IRepositoryBase<T, TId>
where T : Entity<TId> where TId : ITypeIdValueBase
{
Task CreateAsync(TDomain entity, CancellationToken cancellationToken = default);
Task UpdateAsync(TDomain entity, CancellationToken cancellationToken = default);
Task DeleteAsync(TId id, CancellationToken cancellationToken = default);
Task<TDomain> GetByIdAsync(TId id, CancellationToken cancellationToken = default);
Task AddAsync(T entity, CancellationToken cancellationToken);
Task UpdateAsync(T entity, CancellationToken cancellationToken);
Task DeleteAsync(TId id, CancellationToken cancellationToken);
Task DeleteAsync(T entity, CancellationToken cancellationToken);
Task<T?> FindByIdAsync(TId id, CancellationToken cancellationToken);
IQueryable<T> GetQueryAsNoTracking();
}
@@ -0,0 +1,88 @@
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore;
using Vizhvizh.BuildingBlocks.Domain;
public class BaseEntityConfiguration<T, TId, TIdType> : IEntityTypeConfiguration<T>
where T : Entity<TId>
where TId : TypedIdValueBase<TIdType>
{
public virtual void Configure(EntityTypeBuilder<T> builder)
{
// تنظیمات Id
ConfigureId(builder);
// تنظیمات RowVersion
ConfigureRowVersion(builder);
// تنظیمات CreateOn (اگر وجود داشته باشد)
ConfigureCreateOn(builder);
}
private void ConfigureId(EntityTypeBuilder<T> builder)
{
builder.HasKey(x => x.Id);
if (typeof(TIdType) == typeof(int) || typeof(TIdType) == typeof(long))
{
// ❌ مشکل: اینجا نمی‌توانیم به نام جدول دسترسی داشته باشیم
// builder.UseHiLo($"Sequence_{typeof(T).Name}")
// ✅ راه‌حل: در اینجا فقط تنظیمات Id را انجام بده، Hi-Lo را بعداً اعمال کن
builder.Property(x => x.Id)
.HasConversion(
id => id.Value,
value => (TId)Activator.CreateInstance(typeof(TId), value)!);
// ❌ UseHiLo را اینجا نزنید، چون هنوز نام جدول مشخص نیست
}
else if (typeof(TIdType) == typeof(Guid))
{
builder.Property(x => x.Id)
.HasConversion(
id => id.Value,
value => (TId)Activator.CreateInstance(typeof(TId), value)!)
.HasDefaultValueSql("NEWSEQUENTIALID()")
.ValueGeneratedOnAdd();
}
else if (typeof(TIdType) == typeof(string))
{
builder.Property(x => x.Id)
.HasConversion(
id => id.Value,
value => (TId)Activator.CreateInstance(typeof(TId), value)!)
.HasMaxLength(50);
}
}
private void ConfigureRowVersion(EntityTypeBuilder<T> builder)
{
// بررسی وجود خاصیت RowVersion با Reflection
var hasRowVersion = typeof(T).GetProperty("RowVersion") != null;
if (hasRowVersion)
{
// تنظیم RowVersion به عنوان Concurrency Token
builder.Property<byte[]>("RowVersion")
.IsRowVersion() // این یک خط همه کارها را می‌کند
.IsConcurrencyToken()
.ValueGeneratedOnAddOrUpdate();
// برای دیتابیس‌های مختلف:
// builder.Property<byte[]>("RowVersion").HasDefaultValueSql("rowversion");
}
}
private void ConfigureCreateOn(EntityTypeBuilder<T> builder)
{
// تنظیم CreateOn (اگر وجود داشته باشد)
var hasCreateOn = typeof(T).GetProperty("CreateOn") != null;
if (hasCreateOn)
{
builder.Property<DateTime>("CreateOn")
.HasDefaultValueSql("GETDATE()") // SQL Server
// برای PostgreSQL: .HasDefaultValueSql("CURRENT_TIMESTAMP")
// برای MySQL: .HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
}
}
}
@@ -0,0 +1,5 @@
namespace Vizhvizh.BuildingBlocks.Infrastructure.Lifetimes;
public interface IScopeDependency
{
}
@@ -0,0 +1,5 @@
namespace Vizhvizh.BuildingBlocks.Infrastructure.Lifetimes;
public interface ISingletonDependency
{
}
@@ -0,0 +1,5 @@
namespace Vizhvizh.BuildingBlocks.Infrastructure.Lifetimes;
public interface ITransientDependency
{
}
@@ -0,0 +1,92 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Vizhvizh.BuildingBlocks.Domain;
public static class ModelBuilderExtensions
{
public static void AddHiLoSequences(this ModelBuilder modelBuilder)
{
var entityTypes = modelBuilder.Model.GetEntityTypes().Where(x => !x.IsOwned());
foreach (var entityType in entityTypes)
{
var primaryKey = entityType.FindPrimaryKey();
if (primaryKey == null) continue;
var keyProperty = primaryKey.Properties.FirstOrDefault();
if (keyProperty == null) continue;
var actualKeyType = GetUnderlyingKeyType(keyProperty.ClrType);
if (actualKeyType == typeof(int) || actualKeyType == typeof(long))
{
var tableName = entityType.GetTableName();
var sequenceName = GetSequenceName(tableName ?? entityType.Name);
var schema = entityType.GetSchema();
// ایجاد Sequence
if (actualKeyType == typeof(int))
{
modelBuilder.HasSequence<int>(sequenceName, schema)
.StartsAt(1)
.IncrementsBy(1);
}
else
{
modelBuilder.HasSequence<long>(sequenceName, schema)
.StartsAt(1)
.IncrementsBy(1);
}
keyProperty.SetHiLoSequenceName(sequenceName);
keyProperty.SetHiLoSequenceSchema(schema);
keyProperty.SetValueGenerationStrategy(
SqlServerValueGenerationStrategy.SequenceHiLo);
}
}
}
/// <summary>
/// استخراج نوع اصلی از TypedIdValueBase
/// پشتیبانی از:
/// - TypedIdValueBase<int>
/// - TypedIdValueBase<long>
/// - CategoryId : TypedIdValueBase<long>
/// </summary>
private static Type GetUnderlyingKeyType(Type keyType)
{
// حالت 1: خود keyType از نوع TypedIdValueBase<T> باشد
if (keyType.IsGenericType &&
keyType.GetGenericTypeDefinition() == typeof(TypedIdValueBase<>))
{
return keyType.GetGenericArguments()[0];
}
// حالت 2: keyType از TypedIdValueBase<T> ارث‌بری کرده باشد
var baseType = keyType.BaseType;
while (baseType != null && baseType != typeof(object))
{
if (baseType.IsGenericType &&
baseType.GetGenericTypeDefinition() == typeof(TypedIdValueBase<>))
{
return baseType.GetGenericArguments()[0];
}
baseType = baseType.BaseType;
}
// حالت 3: خود keyType int یا long باشد
if (keyType == typeof(int) || keyType == typeof(long) ||
keyType == typeof(int?) || keyType == typeof(long?))
{
return Nullable.GetUnderlyingType(keyType) ?? keyType;
}
// حالت 4: نوع دیگر (مثلاً Guid, string)
return keyType;
}
private static string GetSequenceName(string tableName)
{
return $"Sequence_{tableName}";
}
}
@@ -7,14 +7,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.25" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.25" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.25" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Scrutor" Version="6.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.HierarchyId" Version="8.0.26" />
<PackageReference Include="Microsoft.SqlServer.Types" Version="170.1000.7" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VichVich.BuildingBlocks.Application\Vizhvizh.BuildingBlocks.Application.csproj" />
</ItemGroup>
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using Vizhvizh.BuildingBlocks.Infrastructure;
using Vizhvizh.Shop.ApplicationContract.Commands;
using Vizhvizh.Shop.ApplicationContract.DTOs;
using Vizhvizh.Shop.ApplicationContract.Queries;
@@ -13,6 +14,11 @@ namespace Vizhvizh.Shop.Api.Controllers
public async Task<ActionResult<ShopDTO?>> GetById([FromQuery] long shopId, CancellationToken cancellationToken)
=> Ok(await executor.Execute(new GetShopByIdQuery(shopId), cancellationToken));
[HttpPost]
public async Task<ActionResult> Create([FromBody] CreateShopCommand request, CancellationToken cancellationToken)
{
await executor.Execute(request, cancellationToken);
return Ok();
}
}
}
@@ -7,18 +7,18 @@ using Vizhvizh.Shop.Domain.Shops.ValuesObjects;
namespace Vizhvizh.Shop.Application.CommandHandlers.Shops;
public class CreateShopCommandHandler(IShopRepository shopRepository) : ICommandHandler<CreateShopCommand, ShopId>
public class CreateShopCommandHandler(IShopRepository shopRepository) : ICommandHandler<CreateShopCommand>
{
public async Task<ShopId> Handle(CreateShopCommand request, CancellationToken cancellationToken)
public async Task Handle(CreateShopCommand request, CancellationToken cancellationToken)
{
var location = ShopLocation.CreateNew(request.ShopLocation.Latitude, request.ShopLocation.Longitude,
request.ShopLocation.ProvinceId, request.ShopLocation.CityId, request.ShopLocation.Address, request.ShopLocation.PostalCode);
var businessLicense = ShopBusinessLicense.CreateNew(request.ShopBusinessLicenseImage, request.ShopBusinessLicenseCode);
var shop = Domain.Shops.Entities.Shop.CreateNew(request.OwnerId, request.Title,
location,TelephoneVO.CreateNew(request.Telephone), request.Description);
location, TelephoneVO.CreateNew(request.Telephone), businessLicense, request.Description);
await shopRepository.AddAsync(shop, cancellationToken);
return shop.Id;
}
}
@@ -14,4 +14,8 @@
<ProjectReference Include="..\Vichvich.Shop.ApplicationContract\Vizhvizh.Shop.ApplicationContract.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="CommandHandlers\Products\" />
</ItemGroup>
</Project>
@@ -0,0 +1,8 @@
using Vizhvizh.BuildingBlocks.Domain.Contract;
using Vizhvizh.Shop.ApplicationContract.Models.Products;
using Vizhvizh.Shop.Domain.Products.ValuesObjects;
namespace Vizhvizh.Shop.ApplicationContract.Commands;
public record CreateProductCommand(long ShopId, long CategoryId, string Title, string Description, string Image,
ProductConditionEnum ProductCondition, List<ProductSpecificationsModel> ProductSpecifications) : CommandBase;
@@ -1,9 +1,9 @@
using Vizhvizh.BuildingBlocks.Domain.Contract;
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shop.Domain.Shops.TypeIds;
using Vizhvizh.Shop.Domain.Shops.ValuesObjects;
namespace Vizhvizh.Shop.ApplicationContract.Commands;
public record CreateShopCommand(long OwnerId, string Title,string Telephone, string Description, string Email, ShopLocation ShopLocation) : CommandBase<ShopId>;
public record SetTitleShopCommand(ShopId ShopId,TitleVO Title) : CommandBase;
public record CreateShopCommand(long OwnerId, string Title,string Telephone,string ShopBusinessLicenseImage,string ShopBusinessLicenseCode,
string Description, string Email, ShopLocation ShopLocation) : CommandBase;
public record SetTitleShopCommand(long ShopId,string Title) : CommandBase;
@@ -0,0 +1,3 @@
namespace Vizhvizh.Shop.ApplicationContract.Models.Products;
public record ProductSpecificationsModel(string Title, List<string> Values);
@@ -1,23 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Folder Include="Models\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VichVich.BuildingBlocks.Application\Vizhvizh.BuildingBlocks.Application.csproj" />
<ProjectReference Include="..\Vichvich.Shared.Application\Vizhvizh.Shared.Application.csproj" />
<ProjectReference Include="..\Vichvich.Shop.Domain\Vizhvizh.Shop.Domain.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Vichvich.Shared.Application\Vizhvizh.Shared.Application.csproj" />
<ProjectReference Include="..\Vichvich.Shop.Domain\Vizhvizh.Shop.Domain.csproj" />
</ItemGroup>
</Project>
@@ -2,6 +2,7 @@
using Vizhvizh.Shop.Domain.Members.TypeIds;
using Vizhvizh.Shop.Domain.Members.ValuesObjects;
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shop.Domain.Members.Events;
namespace Vizhvizh.Shop.Domain.Members.Entities;
@@ -10,10 +11,11 @@ public class Member : Entity<MemberId>, IAggregateRoot
private PhoneNumberVO _phoneNumber;
private MemberFullName _fullName;
private MemberAvatar? _avatar;
private MemberNationalCode? _nationalCode;
private Member()
{
}
private Member(PhoneNumberVO phoneNumber, MemberFullName fullName, MemberAvatar? avatar)
{
@@ -28,4 +30,12 @@ public class Member : Entity<MemberId>, IAggregateRoot
public MemberFullName? FullName => _fullName;
public PhoneNumberVO PhoneNumber => _phoneNumber;
public MemberAvatar? Avatar => _avatar;
public MemberNationalCode? NationalCode => _nationalCode;
public void SetNationalCode(MemberNationalCode nationalCode)
{
_nationalCode = nationalCode;
this.AddDomainEvent(new SetNationalCodeEvent(this));
}
}
@@ -0,0 +1,9 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shop.Domain.Members.Entities;
namespace Vizhvizh.Shop.Domain.Members.Events;
public class SetNationalCodeEvent(Member member) : DomainEventBase
{
public Member Member => member;
}
@@ -0,0 +1,17 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Members.ValuesObjects;
public class MemberNationalCode : ValueObject
{
public const short Limit = 10;
public MemberNationalCode(string value)
{
if (value.Length > Limit)
throw new CharacterLimitException(nameof(MemberNationalCode), Limit);
Value = value;
}
public string Value { get; private set; }
}
@@ -27,7 +27,7 @@ public class Specifications : Entity<SpecificationsId>
_product = product;
}
public static Specifications CreateNew(TitleVO title, Product product, List<string> values)
internal static Specifications CreateNew(TitleVO title, Product product, List<string> values)
=> new Specifications(title, product, values);
public TitleVO Title => _title;
@@ -4,6 +4,6 @@ using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.Repositories;
public interface IProductRepository : IRepositoryBase<Product,ProductId>
public interface IProductRepository
{
}
+10 -1
View File
@@ -22,6 +22,8 @@ public class Shop : Entity<ShopId>, IAggregateRoot
private TelephoneVO _telephoneVO;
private ShopLogo _logo;
private MemberId _ownerId;
private ShopStatus _shopStatus;
private ShopBusinessLicense _businessLicense;
private Shop()
{
@@ -32,6 +34,7 @@ public class Shop : Entity<ShopId>, IAggregateRoot
TitleVO title,
ShopLocation location,
TelephoneVO telephone,
ShopBusinessLicense businessLicense,
DescriptionVO? description = null,
EmailVO? email = null
)
@@ -40,18 +43,22 @@ public class Shop : Entity<ShopId>, IAggregateRoot
_title = title;
_location = location;
_description = description;
_businessLicense = businessLicense;
_email = email;
_telephoneVO = telephone;
_shopStatus = ShopStatus.CreateNew(ShopStatusEnum.PendingApproval);
}
public static Shop CreateNew(MemberId ownerId,
TitleVO title,
ShopLocation location,
TelephoneVO telephone,
ShopBusinessLicense businessLicense,
DescriptionVO? description = null,
EmailVO? email = null)
{
return new Shop(ownerId, title, location, telephone, description, email);
return new Shop(ownerId, title, location, telephone, businessLicense, description, email);
}
public MemberId OwnerId => _ownerId;
public Management Management => _management;
@@ -61,6 +68,8 @@ public class Shop : Entity<ShopId>, IAggregateRoot
public EmailVO? Email => _email;
public TelephoneVO Telephone => _telephoneVO;
public ShopLogo Logo => _logo;
public ShopStatus Status => _shopStatus;
public ShopBusinessLicense BusinessLicense => _businessLicense;
public IReadOnlyList<Product> Products => _products;
public IReadOnlyList<ShippingMethod> ShippingMethods => _shippingMethods;
public IReadOnlyList<Member> Members => _members;
@@ -1,9 +1,8 @@
using Vizhvizh.Shop.Domain.Shops.TypeIds;
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shop.Domain.Shops.TypeIds;
namespace Vizhvizh.Shop.Domain.Shops.Repositories;
public interface IShopRepository
public interface IShopRepository : IRepositoryBase<Entities.Shop, ShopId>
{
Task AddAsync(Entities.Shop shop, CancellationToken cancellationToken);
Task<Entities.Shop?> FindByIdAsync(ShopId id, CancellationToken cancellationToken);
}
@@ -0,0 +1,31 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Shops.ValuesObjects;
/// <summary>
/// پروانه کسب
/// </summary>
public class ShopBusinessLicense : ValueObject
{
public const short ImageLimit = 150;
public const short CodeLimit = 50;
private ShopBusinessLicense(string image, string code)
{
if (image.Length > ImageLimit)
throw new CharacterLimitException("ShopBusinessLicenseImage", ImageLimit);
if (code.Length > CodeLimit)
throw new CharacterLimitException("ShopBusinessLicenseCode", CodeLimit);
Image = image;
Code = code;
}
public string Image { get; private set; }
public string Code { get; private set; }
public static ShopBusinessLicense CreateNew(string image, string code)
=> new ShopBusinessLicense(image, code);
}
@@ -0,0 +1,22 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Shops.ValuesObjects;
public class ShopStatus : ValueObject
{
public ShopStatus(ShopStatusEnum value)
{
Value = value;
}
public ShopStatusEnum Value { get; private set; }
public static ShopStatus CreateNew(ShopStatusEnum value)
=> new(value);
}
public enum ShopStatusEnum
{
Creating = 1,
PendingApproval,
Available,
}
@@ -1,10 +1,9 @@
using Vizhvizh.Shop.Domain.Sliders.Entities;
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shop.Domain.Sliders.Entities;
using Vizhvizh.Shop.Domain.Sliders.TypeIds;
namespace Vizhvizh.Shop.Domain.Sliders.Repositories;
public interface ISliderRepository
public interface ISliderRepository : IRepositoryBase<Slider,SliderId>
{
Task AddAsync(Slider slider, CancellationToken cancellationToken);
Task GetByIdAsync(SliderId id,CancellationToken cancellationToken);
}
@@ -12,7 +12,6 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Members\Events\" />
<Folder Include="Members\Rules\" />
<Folder Include="Members\Repositories\" />
<Folder Include="Products\Events\" />
@@ -1,19 +1,18 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shop.Domain.Products.Entities;
using Vizhvizh.Shop.Domain.Products.TypeIds;
using Vizhvizh.Shop.Domain.Products.ValuesObjects;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
internal class CategoryConfiguration : IEntityTypeConfiguration<Category>
internal class CategoryConfiguration : BaseEntityConfiguration<Category,CategoryId ,long>
{
public void Configure(EntityTypeBuilder<Category> builder)
public override void Configure(EntityTypeBuilder<Category> builder)
{
base.Configure(builder);
builder.ToTable("Categories", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Products.TypeIds.CategoryId(x))
.ValueGeneratedOnAdd();
builder.Property(x => x.Title)
.HasField("_title")
@@ -36,9 +35,31 @@ internal class CategoryConfiguration : IEntityTypeConfiguration<Category>
builder.Property(x => x.Path)
.HasField("_path")
.IsRequired()
.HasConversion(x => x.Value, x => Domain.Products.ValuesObjects.CategoryPath.CreateNew(x))
.HasConversion(
// Convert CategoryPath → HierarchyId
categoryPath => HierarchyId.Parse(categoryPath.Value),
// Convert HierarchyId → CategoryPath
hierarchyId => CategoryPath.CreateNew(hierarchyId.ToString()))
.HasColumnType("HIERARCHYID");
// ایندکس برای Path با نوع HIERARCHYID
builder.HasIndex(x => x.Path)
.HasDatabaseName("IX_Categories_Path")
.IsClustered(false); // معمولاً برای HierarchyId بهتر است non-clustered باشد
// رابطه خودارجاع برای ParentId
builder.HasOne<Category>()
.WithMany()
.HasForeignKey(x => x.ParentId)
.HasConstraintName("FK_Categories_ParentId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired(false);
// ایندکس برای ParentId جهت بهبود performance در کوئری‌های سلسله مراتبی
builder.HasIndex(x => x.ParentId)
.HasDatabaseName("IX_Categories_ParentId");
builder.Metadata.FindNavigation(nameof(Category.Products))?
.SetPropertyAccessMode(PropertyAccessMode.Field);
builder.Metadata.FindNavigation(nameof(Category.CategoryVariantUnits))?
@@ -1,18 +1,17 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shop.Domain.Products.Entities;
using Vizhvizh.Shop.Domain.Products.TypeIds;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
internal class CategoryVariantUnitConfiguration : IEntityTypeConfiguration<CategoryVariantUnit>
internal class CategoryVariantUnitConfiguration : BaseEntityConfiguration<CategoryVariantUnit, CategoryVariantUnitId,long>
{
public void Configure(EntityTypeBuilder<CategoryVariantUnit> builder)
public override void Configure(EntityTypeBuilder<CategoryVariantUnit> builder)
{
base.Configure(builder);
builder.ToTable("CategoryVariantUnit", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Products.TypeIds.CategoryVariantUnitId(x))
.ValueGeneratedOnAdd();
builder.Property(x => x.VariantUnitId)
.HasField("_variantUnitId")
@@ -1,17 +1,17 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shop.Domain.Shops.Entities;
using Vizhvizh.Shop.Domain.Shops.TypeIds;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
internal class ManagementConfiguration : IEntityTypeConfiguration<Management>
internal class ManagementConfiguration : BaseEntityConfiguration<Management, ShopId, long>
{
public void Configure(EntityTypeBuilder<Management> builder)
public override void Configure(EntityTypeBuilder<Management> builder)
{
base.Configure(builder);
builder.ToTable("Managements", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Shops.TypeIds.ShopId(x));
builder.Metadata.FindNavigation(nameof(Management.Shop))?
.SetPropertyAccessMode(PropertyAccessMode.Field);
@@ -1,18 +1,18 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shop.Domain.Members.Entities;
using Vizhvizh.Shop.Domain.Members.TypeIds;
using Vizhvizh.Shop.Domain.Members.ValuesObjects;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
internal class MemberConfiguration : IEntityTypeConfiguration<Member>
internal class MemberConfiguration : BaseEntityConfiguration<Member,MemberId , long>
{
public void Configure(EntityTypeBuilder<Member> builder)
public override void Configure(EntityTypeBuilder<Member> builder)
{
base.Configure(builder);
builder.ToTable("Members", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.ValueGeneratedOnAdd();
builder.Property(x => x.PhoneNumber)
.HasField("_phoneNumber");
@@ -32,5 +32,13 @@ internal class MemberConfiguration : IEntityTypeConfiguration<Member>
.HasMaxLength(MemberAvatar.Limit)
.HasColumnName("Avatar");
});
builder.OwnsOne(x => x.NationalCode, sa =>
{
sa.Property(x => x.Value)
.IsRequired(false)
.HasMaxLength(MemberNationalCode.Limit)
.HasColumnName("NationalCode");
});
}
}
@@ -2,19 +2,19 @@
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System.Drawing;
using Vizhvizh.Shop.Domain.Products.Entities;
using Vizhvizh.Shop.Domain.Products.TypeIds;
using Vizhvizh.Shop.Domain.Products.ValuesObjects;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
internal class ProductConfiguration : IEntityTypeConfiguration<Product>
internal class ProductConfiguration : BaseEntityConfiguration<Product,ProductId,long>
{
public void Configure(EntityTypeBuilder<Product> builder)
public override void Configure(EntityTypeBuilder<Product> builder)
{
base.Configure(builder);
builder.ToTable("Products", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Products.TypeIds.ProductId(x))
.ValueGeneratedOnAdd();
builder.OwnsOne(x => x.ProductCondition, sa =>
{
@@ -1,19 +1,19 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shop.Domain.Products.Entities;
using Vizhvizh.Shop.Domain.Products.TypeIds;
using Vizhvizh.Shop.Domain.Products.ValuesObjects;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
internal class ProductVariantConfiguration : IEntityTypeConfiguration<ProductVariant>
internal class ProductVariantConfiguration : BaseEntityConfiguration<ProductVariant,ProductVariantId,long>
{
public void Configure(EntityTypeBuilder<ProductVariant> builder)
public override void Configure(EntityTypeBuilder<ProductVariant> builder)
{
base.Configure(builder);
builder.ToTable("ProductVariants", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Products.TypeIds.ProductVariantId(x))
.ValueGeneratedOnAdd();
builder.OwnsOne(x => x.Score, sa =>
{
@@ -2,19 +2,18 @@
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shop.Domain.Users.Entities;
using Vizhvizh.Shop.Domain.Users.TypeIds;
using Vizhvizh.Shop.Domain.Users.ValueObjects;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
public class ResourceConfiguration : IEntityTypeConfiguration<Resource>
public class ResourceConfiguration : BaseEntityConfiguration<Resource, ResourceId, long>
{
public void Configure(EntityTypeBuilder<Resource> builder)
public override void Configure(EntityTypeBuilder<Resource> builder)
{
base.Configure(builder);
builder.ToTable("Resources", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Users.TypeIds.ResourceId(x))
.ValueGeneratedOnAdd();
builder.Property(x => x.Title)
.HasField("_title");
@@ -23,10 +22,10 @@ public class ResourceConfiguration : IEntityTypeConfiguration<Resource>
builder.Property(x => x.ModuleName)
.HasField("_moduleName")
.HasColumnType("int")
.HasConversion(x=> (int)x.Value, x=> ModuleNameVO.CreateNew((ModuleNamesEnum)x));
.HasConversion(x => (int)x.Value, x => ModuleNameVO.CreateNew((ModuleNamesEnum)x));
builder.Property(x => x.ResourceKey)
.HasConversion(x=>x.Value, x=> ResourceKey.CreateNew(x))
.HasConversion(x => x.Value, x => ResourceKey.CreateNew(x))
.HasField("_resourceKey");
@@ -1,18 +1,18 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shop.Domain.Users.Entities;
using Vizhvizh.Shop.Domain.Users.TypeIds;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
public class RoleConfiguration : IEntityTypeConfiguration<Role>
public class RoleConfiguration : BaseEntityConfiguration<Role,RoleId,int>
{
public void Configure(EntityTypeBuilder<Role> builder)
public override void Configure(EntityTypeBuilder<Role> builder)
{
base.Configure(builder);
builder.ToTable("Roles", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Users.TypeIds.RoleId(x))
.ValueGeneratedOnAdd();
builder.Property(x => x.Title)
.HasField("_title");
@@ -1,19 +1,18 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shop.Domain.Users.Entities;
using Vizhvizh.Shop.Domain.Users.TypeIds;
using Vizhvizh.Shop.Domain.Users.ValueObjects;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
public class RoleResourceConfiguration : IEntityTypeConfiguration<RoleResource>
public class RoleResourceConfiguration : BaseEntityConfiguration<RoleResource,RoleResourceId,long>
{
public void Configure(EntityTypeBuilder<RoleResource> builder)
public override void Configure(EntityTypeBuilder<RoleResource> builder)
{
base.Configure(builder);
builder.ToTable("RoleResources", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Users.TypeIds.RoleResourceId(x))
.ValueGeneratedOnAdd();
builder.Property(x=>x.AccessLevel)
.HasConversion(x=>x.Value, x=> AccessLevel.CreateNew((AccessLevelEnum)x));
@@ -1,19 +1,18 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shop.Domain.Shops.Entities;
using Vizhvizh.Shop.Domain.Shops.TypeIds;
using Vizhvizh.Shop.Domain.Shops.ValuesObjects;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
internal class ShippingMethodConfiguration : IEntityTypeConfiguration<ShippingMethod>
internal class ShippingMethodConfiguration : BaseEntityConfiguration<ShippingMethod,ShippingMethodId ,byte>
{
public void Configure(EntityTypeBuilder<ShippingMethod> builder)
public override void Configure(EntityTypeBuilder<ShippingMethod> builder)
{
base.Configure(builder);
builder.ToTable("ShippingMethods", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Shops.TypeIds.ShippingMethodId(x))
.ValueGeneratedOnAdd();
builder.Property(x => x.Title)
.HasField("_title");
@@ -1,19 +1,18 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shop.Domain.Shops.Entities;
using Vizhvizh.Shop.Domain.Shops.TypeIds;
using Vizhvizh.Shop.Domain.Shops.ValuesObjects;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
public class ShopConfiguration : IEntityTypeConfiguration<Domain.Shops.Entities.Shop>
public class ShopConfiguration : BaseEntityConfiguration<Domain.Shops.Entities.Shop, ShopId, long>
{
public void Configure(EntityTypeBuilder<Domain.Shops.Entities.Shop> builder)
public override void Configure(EntityTypeBuilder<Domain.Shops.Entities.Shop> builder)
{
base.Configure(builder);
builder.ToTable("Shops", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Shops.TypeIds.ShopId(x))
.ValueGeneratedOnAdd();
builder.Property(x => x.OwnerId)
.HasField("_ownerId");
@@ -31,6 +30,17 @@ public class ShopConfiguration : IEntityTypeConfiguration<Domain.Shops.Entities.
.HasMaxLength(ShopLogo.Limit)
.HasColumnName("Logo");
});
builder.OwnsOne(x => x.BusinessLicense, sa =>
{
sa.Property(x => x.Image)
.HasMaxLength(ShopBusinessLicense.ImageLimit)
.HasColumnName("ShopBusinessLicenseImage");
sa.Property(x => x.Code)
.HasMaxLength(ShopBusinessLicense.CodeLimit)
.HasColumnName("ShopBusinessLicenseCode");
});
builder.OwnsOne(x => x.Location, sa =>
{
sa.Property(x => x.PostalCode).HasColumnName(nameof(ShopLocation.PostalCode));
@@ -1,19 +1,18 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shop.Domain.Sliders.Entities;
using Vizhvizh.Shop.Domain.Sliders.TypeIds;
using Vizhvizh.Shop.Domain.Sliders.ValuesObjects;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
internal class SliderConfiguration : IEntityTypeConfiguration<Slider>
internal class SliderConfiguration : BaseEntityConfiguration<Slider,SliderId,long>
{
public void Configure(EntityTypeBuilder<Slider> builder)
public override void Configure(EntityTypeBuilder<Slider> builder)
{
base.Configure(builder);
builder.ToTable("Sliders", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Sliders.TypeIds.SliderId(x))
.ValueGeneratedOnAdd();
builder.Property(x => x.Title)
.HasField("_title");
@@ -2,18 +2,17 @@
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Newtonsoft.Json;
using Vizhvizh.Shop.Domain.Products.Entities;
using Vizhvizh.Shop.Domain.Products.TypeIds;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
internal class SpecificationsConfiguration : IEntityTypeConfiguration<Specifications>
internal class SpecificationsConfiguration : BaseEntityConfiguration<Specifications,SpecificationsId, long>
{
public void Configure(EntityTypeBuilder<Specifications> builder)
public override void Configure(EntityTypeBuilder<Specifications> builder)
{
base.Configure(builder);
builder.ToTable("ProductSpecifications", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x=>x.Value, x=> new Domain.Products.TypeIds.SpecificationsId(x))
.ValueGeneratedOnAdd();
builder.Property(x => x.Title)
.HasField("_title");
@@ -1,17 +1,18 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shop.Domain.Products.Entities;
using Vizhvizh.Shop.Domain.Products.TypeIds;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
internal class UnitConfiguration : IEntityTypeConfiguration<Unit>
internal class UnitConfiguration : BaseEntityConfiguration<Unit, UnitId, long>
{
public void Configure(EntityTypeBuilder<Unit> builder)
public override void Configure(EntityTypeBuilder<Unit> builder)
{
base.Configure(builder);
builder.ToTable("Units", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Products.TypeIds.UnitId(x));
builder.Property(x => x.Title)
.HasField("_title");
@@ -1,18 +1,18 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shop.Domain.Users.Entities;
using Vizhvizh.Shop.Domain.Users.TypeIds;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
public class UserConfiguration : IEntityTypeConfiguration<User>
public class UserConfiguration : BaseEntityConfiguration<User,UserId, long>
{
public void Configure(EntityTypeBuilder<User> builder)
public override void Configure(EntityTypeBuilder<User> builder)
{
base.Configure(builder);
builder.ToTable("Users", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Users.TypeIds.UserId(x))
.ValueGeneratedOnAdd();
//builder.OwnsOne(x => x.NationalCode, sa =>
//{
@@ -1,17 +1,18 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shop.Domain.Products.Entities;
using Vizhvizh.Shop.Domain.Products.TypeIds;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
internal class VariantConfiguration : IEntityTypeConfiguration<Variant>
internal class VariantConfiguration : BaseEntityConfiguration<Variant,VariantId, long>
{
public void Configure(EntityTypeBuilder<Variant> builder)
public override void Configure(EntityTypeBuilder<Variant> builder)
{
base.Configure(builder);
builder.ToTable("Variants", schema: "Shop");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Products.TypeIds.VariantId(x));
builder.Property(x => x.Title)
.HasField("_title");
@@ -1,17 +1,17 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vizhvizh.Shop.Domain.Products.Entities;
using Vizhvizh.Shop.Domain.Products.TypeIds;
namespace Vizhvizh.Shop.Infrastructure.EF.Configurations;
internal class VariantUnitConfiguration : IEntityTypeConfiguration<VariantUnit>
internal class VariantUnitConfiguration : BaseEntityConfiguration<VariantUnit,VariantUnitId,long>
{
public void Configure(EntityTypeBuilder<VariantUnit> builder)
public override void Configure(EntityTypeBuilder<VariantUnit> builder)
{
base.Configure(builder);
builder.ToTable("VariantUnits", schema: "Shop");
builder.HasKey(x=>x.Id);
builder.Property(x => x.Id)
.HasConversion(x => x.Value, x => new Domain.Products.TypeIds.VariantUnitId(x));
builder.Property(x => x.VariantUnitType)
.HasColumnType("INT")
@@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Abstractions;
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shared.Infrastructure.EF.Configurations.Converters;
using Vizhvizh.Shop.Domain.Members.TypeIds;
@@ -36,15 +37,7 @@ internal class ShopDbContext : DbContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(Assemblies.Infrastructure, FindConfigurations);
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
var createOnProperty = entityType.FindProperty("CreateOn");
if (createOnProperty != null && createOnProperty.ClrType == typeof(DateTime))
{
createOnProperty.SetDefaultValueSql("GETDATE()");
}
}
modelBuilder.AddHiLoSequences();
}
public bool FindConfigurations(Type type)
=> type?.FullName?.Contains("Configurations") ?? false;
@@ -0,0 +1,10 @@
namespace Vizhvizh.Shop.Infrastructure.Exceptions;
public class EntityNotFoundException : Exception
{
public EntityNotFoundException()
: base("entity not found")
{
}
}
@@ -1,15 +1,16 @@
using Vizhvizh.Shop.Domain.Shops.Repositories;
using Vizhvizh.BuildingBlocks.Infrastructure.Lifetimes;
using Vizhvizh.Shop.Domain.Shops.Repositories;
using Vizhvizh.Shop.Domain.Shops.TypeIds;
using Vizhvizh.Shop.Infrastructure.EF;
namespace Vizhvizh.Shop.Infrastructure.Repositories
{
internal class ShopRepository(ShopDbContext context) : IShopRepository
internal class ShopRepository(ShopDbContext context) : RepositoryBase<Domain.Shops.Entities.Shop, ShopId>(context), IShopRepository, IScopeDependency
{
public async Task AddAsync(Domain.Shops.Entities.Shop shop, CancellationToken cancellationToken)
=> await context.Shops.AddAsync(shop, cancellationToken);
public async Task<Domain.Shops.Entities.Shop?> FindByIdAsync(ShopId id, CancellationToken cancellationToken)
=> await context.Shops.FindAsync(id,cancellationToken).ConfigureAwait(false);
=> await context.Shops.FindAsync(id, cancellationToken).ConfigureAwait(false);
}
}
@@ -1,18 +1,12 @@
using Vizhvizh.Shop.Domain.Sliders.Entities;
using Vizhvizh.BuildingBlocks.Infrastructure.Lifetimes;
using Vizhvizh.Shop.Domain.Sliders.Entities;
using Vizhvizh.Shop.Domain.Sliders.Repositories;
using Vizhvizh.Shop.Domain.Sliders.TypeIds;
using Vizhvizh.Shop.Infrastructure.EF;
namespace Vizhvizh.Shop.Infrastructure.Repositories;
public class SliderRepository : ISliderRepository
internal class SliderRepository(ShopDbContext context) : RepositoryBase<Slider, SliderId>(context), ISliderRepository, IScopeDependency
{
public Task AddAsync(Slider slider, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task GetByIdAsync(SliderId id, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
@@ -0,0 +1,52 @@
using Microsoft.EntityFrameworkCore;
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shop.Infrastructure.EF;
using Vizhvizh.Shop.Infrastructure.Exceptions;
namespace Vizhvizh.Shop.Infrastructure;
internal class RepositoryBase<T, TId> : IRepositoryBase<T, TId>
where T : Entity<TId> where TId : ITypeIdValueBase
{
private readonly ShopDbContext _shopDbContext;
public RepositoryBase(ShopDbContext shopDbContext)
{
this._shopDbContext = shopDbContext;
}
public async Task AddAsync(T entity, CancellationToken cancellationToken)
{
await _shopDbContext.AddAsync(entity, cancellationToken);
}
public async Task DeleteAsync(TId id, CancellationToken cancellationToken)
{
var entity = await FindByIdAsync(id, cancellationToken);
if (entity == null)
throw new EntityNotFoundException();
_shopDbContext.Remove(entity);
}
public Task DeleteAsync(T entity, CancellationToken cancellationToken)
{
_shopDbContext.Remove(entity);
return Task.CompletedTask;
}
public async Task<T?> FindByIdAsync(TId id, CancellationToken cancellationToken)
{
var entity = _shopDbContext.Set<T>();
return await entity.FindAsync(id, cancellationToken);
}
public IQueryable<T> GetQueryAsNoTracking()
=> _shopDbContext.Set<T>().AsNoTracking();
public Task UpdateAsync(T entity, CancellationToken cancellationToken)
{
_shopDbContext.Update(entity);
return Task.CompletedTask;
}
}
+16 -7
View File
@@ -15,6 +15,7 @@ using Vizhvizh.Shop.Infrastructure.Repositories;
using Vizhvizh.BuildingBlocks.Infrastructure.SelectBuilders;
using Vizhvizh.BuildingBlocks.Application.SelectBuilders;
using Vizhvizh.Shop.Domain.Sliders.Repositories;
using Vizhvizh.BuildingBlocks.Infrastructure.Lifetimes;
namespace Vizhvizh.Shop.Infrastructure;
@@ -25,7 +26,7 @@ public class ShopStartup
{
services.AddDbContext<ShopDbContext>(op =>
{
op.UseSqlServer(connectionString);
op.UseSqlServer(connectionString, sqlOption=> sqlOption.UseHierarchyId());
});
services.AddScoped<DbContext>(sp => sp.GetRequiredService<ShopDbContext>());
services.AddScoped<IShopModule, ShopModule>();
@@ -36,6 +37,7 @@ public class ShopStartup
services.AddScoped<IExecutor, Executor>();
services.Scan(scan => scan.
FromAssemblies(Assemblies.Application, Assemblies.Infrastructure)
.AddClasses(classes => classes.AssignableTo(typeof(ICommandHandler<>)), publicOnly: false)
.AsImplementedInterfaces()
.WithScopedLifetime()
@@ -47,7 +49,19 @@ public class ShopStartup
.WithScopedLifetime()
.AddClasses(classes => classes.AssignableTo(typeof(ICommandHandler<>)), publicOnly: false)
.AsImplementedInterfaces()
.WithScopedLifetime());
.WithScopedLifetime()
.AddClasses(classes => classes.AssignableTo(typeof(ISingletonDependency)), publicOnly: false)
.AsImplementedInterfaces()
.WithSingletonLifetime()
.AddClasses(classes => classes.AssignableTo(typeof(IScopeDependency)), publicOnly: false)
.AsImplementedInterfaces()
.WithScopedLifetime()
.AddClasses(classes => classes.AssignableTo(typeof(ITransientDependency)), publicOnly: false)
.AsImplementedInterfaces()
.WithTransientLifetime()
);
services.Decorate(typeof(ICommandHandler<>), typeof(UnitOfWorkCommandHandlerDecorator<>));
services.Decorate(typeof(ICommandHandler<,>), typeof(UnitOfWorkCommandHandlerDecorator<,>));
services.AddScoped(sa =>
@@ -71,10 +85,5 @@ public class ShopStartup
services.AddScoped<ISqlDialect, SqlServerDialect>();
services.AddScoped<ISqlSelectBuilder, SqlSelectBuilder>();
#region Repositories
services.AddScoped<IShopRepository, ShopRepository>();
services.AddScoped<ISliderRepository, SliderRepository>();
#endregion
}
}
@@ -19,7 +19,6 @@
<ItemGroup>
<ProjectReference Include="..\Vichvich.Shared.Infrastructure\Vizhvizh.Shared.Infrastructure.csproj" />
<ProjectReference Include="..\Vichvich.Shop.Application\Vizhvizh.Shop.Application.csproj" />
<ProjectReference Include="..\Vichvich.Shop.Domain\Vizhvizh.Shop.Domain.csproj" />
</ItemGroup>
</Project>
+4 -4
View File
@@ -6,21 +6,21 @@ namespace Vizhvizh.UserAccess.Domain.Entities;
public class User : Entity<UserId>, IAggregateRoot
{
private UserNationalCode _nationalCode;
private MemberNationalCode _nationalCode;
private MemberId _memberId;
private List<Role> _roles;
private User(UserNationalCode nationalCode,MemberId memberId,List<Role> roles)
private User(MemberNationalCode nationalCode,MemberId memberId,List<Role> roles)
{
_nationalCode = nationalCode;
_memberId = memberId;
_roles = roles;
}
public static User CreateNew(UserNationalCode nationalCode, MemberId memberId, List<Role> roles)
public static User CreateNew(MemberNationalCode nationalCode, MemberId memberId, List<Role> roles)
=> new User(nationalCode, memberId, roles);
public UserNationalCode NationalCode => _nationalCode;
public MemberNationalCode NationalCode => _nationalCode;
public MemberId MemberId => _memberId;
public IReadOnlyList<Role> Roles => _roles;
}
@@ -0,0 +1,48 @@
using Vizhvizh.UserAccess.Domain.Exceptions;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.UserAccess.Domain.ValueObjects;
public class MemberNationalCode : ValueObject
{
public static bool IsValidNationalCode(string nationalCode)
{
if (nationalCode is null || nationalCode.Length > 10)
return false;
// تبدیل به آرایه
var arr = nationalCode.ToArray().Select(n => int.Parse(n.ToString()));
//بر عکس کردن اجزا
var arrReduce = arr.Reverse().ToList();
// بدست آوردن رقم کنترل اخر کد ملی
var numberControl = arrReduce.First();
arrReduce.RemoveAt(0);
// تمام 9 رقم سمت چپ کد ملی ضرب در موقعیت خودش میشه بعد همه جمع میشن بعدش تقسیم به یازده و باقی مانده رو میگیرم
//کد ملی 0700454713
//موقیعت 07 به ترتیب 9و10 هست از اونجایی ک ما رقم کنترل رو برداشتیم پس باید ایندکس ب اضافه ی 2 شه
var remaining = decimal.Parse($"{arrReduce.Select((n, i) => n * (i + 2)).Sum() % 11}");
if (remaining <= 2.0m)
{
if (numberControl == remaining)
return true;
else
return false;
}
else if (11m - remaining == numberControl)
return true;
else
return false;
}
public MemberNationalCode(string value)
{
if (!IsValidNationalCode(value))
throw new InvalidNationalCodeException();
Value = value;
}
public string Value { get; init; }
}
@@ -0,0 +1,36 @@
using Vizhvizh.BuildingBlocks.Application.Contract;
namespace Vizhvizh.GoldGallery.Api.Configurations
{
public class ExecutionContextAccessor : IExecutionContextAccessor
{
private readonly IHttpContextAccessor _httpContextAccessor;
public ExecutionContextAccessor(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public Guid UserId
{
get
{
if (_httpContextAccessor
.HttpContext?
.User?
.Claims?
.SingleOrDefault(x => x.Type == "sub")?
.Value != null)
{
return Guid.Parse(_httpContextAccessor.HttpContext.User.Claims.Single(
x => x.Type == "sub").Value);
}
throw new ApplicationException("User context is not available");
}
}
public bool IsAvailable => _httpContextAccessor.HttpContext != null;
}
}
@@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Mvc;
using Vizhvizh.BuildingBlocks.Infrastructure;
using Vizhvizh.GoldGallery.ApplicationContract.Commands;
namespace Vizhvizh.GoldGallery.Api.Controllers;
[ApiController]
[Route("api/[controller]/[action]")]
public class CategoryController(IExecutor executor) : ControllerBase
{
[HttpPost]
public async Task<ActionResult> Create([FromBody] CreateCategoryCommand request, CancellationToken cancellationToken)
{
await executor.Execute(request, cancellationToken);
return Ok();
}
}
@@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Mvc;
using Vizhvizh.BuildingBlocks.Infrastructure;
using Vizhvizh.GoldGallery.ApplicationContract.Commands;
namespace Vizhvizh.GoldGallery.Api.Controllers;
[ApiController]
[Route("api/[controller]/[action]")]
public class ProductController(IExecutor executor) : ControllerBase
{
[HttpPost]
public async Task<ActionResult> Create([FromBody] CreateProductCommand request, CancellationToken cancellationToken)
{
await executor.Execute(request, cancellationToken);
return Ok();
}
}
@@ -0,0 +1,24 @@
using Microsoft.AspNetCore.Mvc;
using Vizhvizh.BuildingBlocks.Infrastructure;
using Vizhvizh.GoldGallery.ApplicationContract.Commands;
using Vizhvizh.GoldGallery.ApplicationContract.DTOs;
using Vizhvizh.GoldGallery.ApplicationContract.Queries;
namespace Vizhvizh.GoldGallery.Api.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class ShopController(IExecutor executor) : ControllerBase
{
[HttpGet]
public async Task<ActionResult<ShopDTO?>> GetById([FromQuery] long shopId, CancellationToken cancellationToken)
=> Ok(await executor.Execute(new GetShopByIdQuery(shopId), cancellationToken));
[HttpPost]
public async Task<ActionResult> Create([FromBody] CreateShopCommand request, CancellationToken cancellationToken)
{
await executor.Execute(request, cancellationToken);
return Ok();
}
}
}
@@ -0,0 +1,45 @@
using Microsoft.AspNetCore.Mvc;
using Vizhvizh.BuildingBlocks.Infrastructure;
using Vizhvizh.GoldGallery.Api.RequestModels;
using Vizhvizh.GoldGallery.ApplicationContract.Commands;
using Vizhvizh.GoldGallery.ApplicationContract.DTOs;
using Vizhvizh.GoldGallery.ApplicationContract.Queries;
using Vizhvizh.GoldGallery.Domain.Sliders.ValuesObjects;
namespace Vizhvizh.GoldGallery.Api.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class SliderController(IExecutor executor) : ControllerBase
{
[HttpPost]
public async Task<ActionResult> AddMainSlider([FromBody] CreateSliderRequestModel request, CancellationToken cancellationToken)
{
await executor.Execute(new CreateSliderCommand(request.Title, request.ImageUrl, request.LinkUrl, SliderKeyType.Main, null), cancellationToken);
return Ok();
}
[HttpPost]
public async Task<ActionResult> AddShopSlider([FromHeader] long shopId, [FromBody] CreateSliderRequestModel request, CancellationToken cancellationToken)
{
await executor.Execute(new CreateSliderCommand(request.Title, request.ImageUrl, request.LinkUrl, SliderKeyType.Shop, shopId.ToString()), cancellationToken);
return Ok();
}
[HttpPost]
public async Task<ActionResult> AddCategorySlider([FromHeader] long categoryId, [FromBody] CreateSliderRequestModel request, CancellationToken cancellationToken)
{
await executor.Execute(new CreateSliderCommand(request.Title, request.ImageUrl, request.LinkUrl, SliderKeyType.Category, categoryId.ToString()), cancellationToken);
return Ok();
}
[HttpGet]
public async Task<ActionResult<IEnumerable<SliderDTO>>> GetByKey([FromQuery] GetSlidersByKeyQuery request,CancellationToken cancellationToken)
{
var result = await executor.Execute(request,cancellationToken);
return Ok(result);
}
}
}
+33
View File
@@ -0,0 +1,33 @@
using Vizhvizh.BuildingBlocks.Application.Contract;
using Vizhvizh.GoldGallery.Api.Configurations;
using Vizhvizh.GoldGallery.Infrastructure;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddSingleton<IExecutionContextAccessor, ExecutionContextAccessor>();
GoldGalleryStartup.Initialize(builder.Services, builder.Configuration.GetConnectionString("GoldGallery")!);
builder.Services.AddControllers();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseSwagger();
app.UseSwaggerUI(opt =>
{
opt.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
});
//app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
@@ -0,0 +1,41 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:46206",
"sslPort": 44384
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "weatherforecast",
"applicationUrl": "http://localhost:5210",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "weatherforecast",
"applicationUrl": "https://localhost:7209;http://localhost:5210",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
@@ -0,0 +1,3 @@
namespace Vizhvizh.GoldGallery.Api.RequestModels;
public record CreateSliderRequestModel(string Title,string ImageUrl, string LinkUrl);
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>false</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.25">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Vizhvizh.GoldGallery.Infrastructure\Vizhvizh.GoldGallery.Infrastructure.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,6 @@
@Vizhvizh.GoldGallery.Api_HostAddress = http://localhost:5210
GET {{Vizhvizh.GoldGallery.Api_HostAddress}}/weatherforecast/
Accept: application/json
###
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
+12
View File
@@ -0,0 +1,12 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"GoldGallery": "Data Source=.;Initial Catalog=Vizhvizh.GoldGallery;Integrated Security=True;Trusted_Connection=True; MultipleActiveResultSets=true;TrustServerCertificate=True;"
},
"AllowedHosts": "*"
}
@@ -0,0 +1,34 @@
using Microsoft.EntityFrameworkCore;
using Vizhvizh.BuildingBlocks.Application.Configuration.Commnad;
using Vizhvizh.GoldGallery.ApplicationContract.Commands;
using Vizhvizh.GoldGallery.Domain.Products.Entities;
using Vizhvizh.GoldGallery.Domain.Products.Repositories;
using Vizhvizh.GoldGallery.Domain.Products.ValuesObjects;
namespace Vizhvizh.GoldGallery.Application.CommandHandlers.Categories;
public class CreateCategoryCommandHandler(ICategoryRepository categoryRepository) : ICommandHandler<CreateCategoryCommand>
{
public async Task Handle(CreateCategoryCommand request, CancellationToken cancellationToken)
{
CategoryPath? parentPath = null;
if(request.ParentId != null)
{
parentPath = await categoryRepository.GetQueryAsNoTracking()
.Where(x => x.Id == request.ParentId)
.Select(x => x.Path)
.FirstOrDefaultAsync(cancellationToken);
}
var category = Category.CreateNew(request.Title,
request.Description,
request.Image,
request.ParentId);
await categoryRepository.AddAsync(category, cancellationToken);
category.SetPath(parentPath);
}
}
@@ -0,0 +1,38 @@
using FluentValidation;
using Microsoft.EntityFrameworkCore;
using Vizhvizh.BuildingBlocks.Application.Configuration.Commnad;
using Vizhvizh.GoldGallery.ApplicationContract.Commands;
using Vizhvizh.GoldGallery.Domain.Products.Entities;
using Vizhvizh.GoldGallery.Domain.Products.Repositories;
using Vizhvizh.GoldGallery.Domain.Resource.Products;
namespace Vizhvizh.GoldGallery.Application.CommandHandlers.Products;
public class CreateProductCommandHandler(IProductRepository productRepository,
ICategoryRepository categoryRepository) : ICommandHandler<CreateProductCommand>
{
public async Task Handle(CreateProductCommand request, CancellationToken cancellationToken)
{
var category = (await categoryRepository.FindByIdAsync(request.CategoryId, cancellationToken))!;
var specifications = request.ProductSpecifications.Select(x => Specifications.CreateNew(x.Title, x.Values)).ToList();
var productVariantImage = request.ProductVariants.Select(x => x.Gallery).ToList();
var productVariants = request.ProductVariants.Select(x => ProductVariant.CreateNew(x.Quantity, x.Weight, x.Gallery)).ToList();
var product = Product.CreateNew(request.Title, request.Description,
request.ProductCondition, category, specifications, productVariants, request.Image, request.File3D, request.CraftsmanshipFee);
await productRepository.AddAsync(product, cancellationToken);
}
}
public class CreateProductCommandValidator : AbstractValidator<CreateProductCommand>
{
public CreateProductCommandValidator(ICategoryRepository categoryRepository)
{
RuleFor(x => x.CategoryId)
.MustAsync(async (id, cancellation) =>
{
return await categoryRepository.GetQueryAsNoTracking().AnyAsync(x => x.Id == id);
}).WithMessage(m => string.Format(ValidationResources.NotFoundCategoryById, m.CategoryId));
}
}
@@ -0,0 +1,33 @@
using Vizhvizh.BuildingBlocks.Application.Configuration.Commnad;
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.GoldGallery.ApplicationContract.Commands;
using Vizhvizh.GoldGallery.Domain.Shops.Repositories;
using Vizhvizh.GoldGallery.Domain.Shops.TypeIds;
using Vizhvizh.GoldGallery.Domain.Shops.ValuesObjects;
using FluentValidation;
namespace Vizhvizh.GoldGallery.Application.CommandHandlers.Shops;
public class CreateShopCommandHandler(IShopRepository shopRepository) : ICommandHandler<CreateShopCommand>
{
public async Task Handle(CreateShopCommand request, CancellationToken cancellationToken)
{
var location = ShopLocation.CreateNew(request.ShopLocation.Latitude, request.ShopLocation.Longitude,
request.ShopLocation.ProvinceId, request.ShopLocation.CityId, request.ShopLocation.Address, request.ShopLocation.PostalCode);
var businessLicense = ShopBusinessLicense.CreateNew(request.ShopBusinessLicenseImage, request.ShopBusinessLicenseCode);
var shop = Domain.Shops.Entities.Shop.CreateNew(request.OwnerId, request.Title,
location, TelephoneVO.CreateNew(request.Telephone), businessLicense, request.Description);
await shopRepository.AddAsync(shop, cancellationToken);
}
}
public class CreateShopCommandValidator : AbstractValidator<CreateShopCommand>
{
public CreateShopCommandValidator()
{
}
}
@@ -0,0 +1,14 @@
using Vizhvizh.BuildingBlocks.Application.Configuration.Commnad;
using Vizhvizh.GoldGallery.ApplicationContract.Commands;
using Vizhvizh.GoldGallery.Domain.Shops.Repositories;
namespace Vizhvizh.GoldGallery.Application.CommandHandlers.Shops;
public class SetTitleShopCommandHandler(IShopRepository shopRepository) : ICommandHandler<SetTitleShopCommand>
{
public async Task Handle(SetTitleShopCommand request, CancellationToken cancellationToken)
{
var shop = await shopRepository.FindByIdAsync(request.ShopId, cancellationToken);
shop.SetTitle(request.Title);
}
}
@@ -0,0 +1,18 @@
using Vizhvizh.BuildingBlocks.Application.Configuration.Commnad;
using Vizhvizh.GoldGallery.ApplicationContract.Commands;
using Vizhvizh.GoldGallery.Domain.Sliders.Entities;
using Vizhvizh.GoldGallery.Domain.Sliders.Repositories;
using Vizhvizh.GoldGallery.Domain.Sliders.ValuesObjects;
namespace Vizhvizh.GoldGallery.Application.CommandHandlers.Sliders;
public class CreateSliderCommandHandler(ISliderRepository sliderRepository) : ICommandHandler<CreateSliderCommand>
{
public async Task Handle(CreateSliderCommand request, CancellationToken cancellationToken)
{
var slider = Slider.CreateNew(request.Title, SliderImage.CreateNew(request.ImageUrl),
SliderUrl.CreateNew(request.LinkUrl), new SliderKey(request.SliderKeyType, request.SliderKey));
await sliderRepository.AddAsync(slider, cancellationToken);
}
}
@@ -0,0 +1,22 @@
using FluentValidation;
using Vizhvizh.BuildingBlocks.Application.Configuration.Commnad;
using Vizhvizh.GoldGallery.ApplicationContract.Commands;
namespace Vizhvizh.GoldGallery.Application.CommandHandlers
{
public class TestCommandHandler : ICommandHandler<TestCommand, Guid>
{
public Task<Guid> Handle(TestCommand request, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
public class TestCommandValidator : AbstractValidator<TestCommand>
{
public TestCommandValidator()
{
}
}
}
@@ -0,0 +1,13 @@
using Vizhvizh.BuildingBlocks.Application.Contract;
using Vizhvizh.BuildingBlocks.Domain.Contract;
namespace Vizhvizh.GoldGallery.Application;
public interface IGoldGalleryModule
{
Task<TResult> ExecuteCommandAsync<TResult>(ICommand<TResult> command,CancellationToken cancellationToken);
Task ExecuteCommandAsync(ICommand command, CancellationToken cancellationToken);
Task<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query, CancellationToken cancellationToken);
}
@@ -0,0 +1,33 @@
using Dapper;
using Vizhvizh.BuildingBlocks.Application.Configuration.Query;
using Vizhvizh.BuildingBlocks.Application.Data;
using Vizhvizh.BuildingBlocks.Application.SelectBuilders;
using Vizhvizh.GoldGallery.ApplicationContract.DTOs;
using Vizhvizh.GoldGallery.ApplicationContract.Queries;
namespace Vizhvizh.GoldGallery.Application.QueryHandlers.Shops;
public class GetShopByIdQueryHandler(ISqlConnectionFactory connectionFactory, ISqlSelectBuilder sqlSelectBuilder) : IQueryHandler<GetShopByIdQuery, ShopDTO?>
{
public async Task<ShopDTO?> Handle(GetShopByIdQuery request, CancellationToken cancellationToken)
{
var connection = connectionFactory.GetOpenConnection();
var (sql, parameters) = sqlSelectBuilder
.From("Shop.Shops")
.Select<Domain.Shops.Entities.Shop, ShopDTO>(
(d => d.Id, dto => dto.Id),
(d => d.OwnerId, dto => dto.OwnerId),
(d => d.Title, dto => dto.Title),
(d => d.Description, dto => dto.Description),
(d => d.Email, dto => dto.Email),
(d => d.Telephone, dto => dto.Telephone),
(d => d.Logo, dto => dto.Logo)
)
.Where<ShopDTO>(s => s.Id, request.ShopId)
.Build();
var result = await connection.QueryFirstOrDefaultAsync<ShopDTO>(sql, parameters);
return result;
}
}
@@ -0,0 +1,31 @@
using Dapper;
using Vizhvizh.BuildingBlocks.Application.Configuration.Query;
using Vizhvizh.BuildingBlocks.Application.Data;
using Vizhvizh.BuildingBlocks.Application.SelectBuilders;
using Vizhvizh.GoldGallery.ApplicationContract.DTOs;
using Vizhvizh.GoldGallery.ApplicationContract.Queries;
using Vizhvizh.GoldGallery.Domain.Sliders.Entities;
namespace Vizhvizh.GoldGallery.Application.QueryHandlers.Sliders;
public class GetSlidersByKeyQueryHandler(ISqlConnectionFactory sqlConnectionFactory, ISqlSelectBuilder sqlSelectBuilder)
: IQueryHandler<GetSlidersByKeyQuery, IEnumerable<SliderDTO>>
{
public async Task<IEnumerable<SliderDTO>> Handle(GetSlidersByKeyQuery request, CancellationToken cancellationToken)
{
var connection = sqlConnectionFactory.GetOpenConnection();
var (sql, parameters) = sqlSelectBuilder.From("Shop.Sliders")
.Select<Slider, SliderDTO>(
(d => d.Title, dto => dto.Title),
(d => d.Image, dto => dto.Image),
(d => d.Url, dto => dto.LinkUrl)
)
.Pagination<Slider>(request.PageNumber, request.PageSize, x => x.CreateOn, false)
.Where<Slider>(x => x.Key, request.Key)
.Build();
var result = await connection.QueryAsync<SliderDTO>(sql, parameters);
return result;
}
}
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dapper" Version="2.1.72" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Vizhvizh.GoldGallery.ApplicationContract\Vizhvizh.GoldGallery.ApplicationContract.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,7 @@
using Vizhvizh.BuildingBlocks.Domain.Contract;
namespace Vizhvizh.GoldGallery.ApplicationContract.Commands;
public record CreateCategoryCommand(string Title, string Description, string Image, long? ParentId) : CommandBase;
public record UpdateCategoryCommand(long CategoryId, string Title, string Description, string Image, long? ParentId) : CommandBase;
public record DeleteCategoryCommand(long CategoryId) : CommandBase;
@@ -0,0 +1,9 @@
using Vizhvizh.BuildingBlocks.Domain.Contract;
using Vizhvizh.GoldGallery.ApplicationContract.Models.Products;
using Vizhvizh.GoldGallery.Domain.Products.ValuesObjects;
namespace Vizhvizh.GoldGallery.ApplicationContract.Commands;
public record CreateProductCommand(long ShopId, long CategoryId, string Title, string Description, string Image, decimal CraftsmanshipFee,
ProductConditionEnum ProductCondition, string? File3D, List<CreateProductModel.SpecificationsModel> ProductSpecifications,
List<CreateProductModel.ProductVariant> ProductVariants) : CommandBase;
@@ -0,0 +1,9 @@
using Vizhvizh.BuildingBlocks.Domain.Contract;
using Vizhvizh.GoldGallery.Domain.Shops.TypeIds;
using Vizhvizh.GoldGallery.Domain.Shops.ValuesObjects;
namespace Vizhvizh.GoldGallery.ApplicationContract.Commands;
public record CreateShopCommand(long OwnerId, string Title,string Telephone,string ShopBusinessLicenseImage,string ShopBusinessLicenseCode,
string Description, string Email, ShopLocation ShopLocation) : CommandBase;
public record SetTitleShopCommand(long ShopId,string Title) : CommandBase;
@@ -0,0 +1,6 @@
using Vizhvizh.BuildingBlocks.Domain.Contract;
using Vizhvizh.GoldGallery.Domain.Sliders.ValuesObjects;
namespace Vizhvizh.GoldGallery.ApplicationContract.Commands;
public record CreateSliderCommand(string Title, string ImageUrl,string LinkUrl, SliderKeyType SliderKeyType, string? SliderKey) : CommandBase;
@@ -0,0 +1,6 @@
using Vizhvizh.BuildingBlocks.Domain.Contract;
namespace Vizhvizh.GoldGallery.ApplicationContract.Commands
{
public record TestCommand() : CommandBase<Guid>;
}
@@ -0,0 +1,13 @@
namespace Vizhvizh.GoldGallery.ApplicationContract.DTOs;
public class ShopDTO
{
public long Id { get; set; }
public long OwnerId{ get; set; }
public string Title { get; set; } = null!;
public string? Description{ get; set; }
public string? Email { get; set; }
public string Telephone { get; set; } = null!;
public string Logo{ get; set; } = null!;
public ShopLocationDTO ShopLocation { get; set; } = null!;
}
@@ -0,0 +1,9 @@
using Newtonsoft.Json;
namespace Vizhvizh.GoldGallery.ApplicationContract.DTOs;
public record ShopLocationDTO(double Latitude,double Longitude,int ProvinceId, int CityId,string Address, string PostalCode)
{
public static implicit operator ShopLocationDTO(string address)
=> JsonConvert.DeserializeObject<ShopLocationDTO>(address)!;
}
@@ -0,0 +1,3 @@
namespace Vizhvizh.GoldGallery.ApplicationContract.DTOs;
public record SliderDTO(string Title, string Image,string LinkUrl);
@@ -0,0 +1,7 @@
namespace Vizhvizh.GoldGallery.ApplicationContract.Models.Products;
public class CreateProductModel
{
public record SpecificationsModel(string Title, List<string> Values);
public record ProductVariant(double Quantity, decimal Weight, List<string> Gallery);
}
@@ -0,0 +1,7 @@
namespace Vizhvizh.GoldGallery.ApplicationContract.Queries;
public class PaginationQuery
{
public int PageNumber { get; set; }
public int PageSize { get; set; }
}
@@ -0,0 +1,7 @@
using Vizhvizh.BuildingBlocks.Domain.Contract;
using Vizhvizh.GoldGallery.ApplicationContract.DTOs;
using Vizhvizh.GoldGallery.Domain.Shops.TypeIds;
namespace Vizhvizh.GoldGallery.ApplicationContract.Queries;
public record GetShopByIdQuery(long ShopId) : IQuery<ShopDTO?>;
@@ -0,0 +1,9 @@
using Vizhvizh.BuildingBlocks.Domain.Contract;
using Vizhvizh.GoldGallery.ApplicationContract.DTOs;
namespace Vizhvizh.GoldGallery.ApplicationContract.Queries;
public class GetSlidersByKeyQuery : PaginationQuery, IQuery<IEnumerable<SliderDTO>>
{
public string Key { get; set; }
}
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Vichvich.Shared.Application\Vizhvizh.Shared.Application.csproj" />
<ProjectReference Include="..\Vizhvizh.GoldGallery.Domain\Vizhvizh.GoldGallery.Domain.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Vizhvizh.GoldGallery.Domain.Resource.Members {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class EntityResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal EntityResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Vizhvizh.GoldGallery.Domain.Resource.Members.EntityResources", typeof(EntityResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -0,0 +1,72 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Vizhvizh.GoldGallery.Domain.Resource.Members {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class ExceptionResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal ExceptionResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Vizhvizh.GoldGallery.Domain.Resource.Members.ExceptionResources", typeof(ExceptionResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to نام یا نام خانوادگی نمیتواند خالی باشد.
/// </summary>
public static string MemberFullNameNullOrEmptyException {
get {
return ResourceManager.GetString("MemberFullNameNullOrEmptyException", resourceCulture);
}
}
}
}
@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="MemberFullNameNullOrEmptyException" xml:space="preserve">
<value>نام یا نام خانوادگی نمیتواند خالی باشد</value>
</data>
</root>
@@ -0,0 +1,72 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Vizhvizh.GoldGallery.Domain.Resource.Members {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class ValueObjectResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal ValueObjectResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Vizhvizh.GoldGallery.Domain.Resource.Members.ValueObjectResources", typeof(ValueObjectResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to نام و نام خانوادگی.
/// </summary>
public static string MemberFullName {
get {
return ResourceManager.GetString("MemberFullName", resourceCulture);
}
}
}
}
@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="MemberFullName" xml:space="preserve">
<value>نام و نام خانوادگی</value>
</data>
</root>
@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Vizhvizh.GoldGallery.Domain.Resource.Products {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class EntityResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal EntityResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Vizhvizh.GoldGallery.Domain.Resource.Products.EntityResources", typeof(EntityResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -0,0 +1,99 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Vizhvizh.GoldGallery.Domain.Resource.Products {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class ExceptionResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal ExceptionResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Vizhvizh.GoldGallery.Domain.Resource.Products.ExceptionResources", typeof(ExceptionResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to اجرت نمی‌تواند منفی باشد.
/// </summary>
public static string CraftsmanshipFeeCannotBeNegativeException {
get {
return ResourceManager.GetString("CraftsmanshipFeeCannotBeNegativeException", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to وزن طلا باید بزرگتر از {0} گرم باشد.
/// </summary>
public static string GoldWeightMustGreaterThanException {
get {
return ResourceManager.GetString("GoldWeightMustGreaterThanException", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to اجرت نامعتبر می‌باشد.
/// </summary>
public static string InvalidCraftsmanshipFeeException {
get {
return ResourceManager.GetString("InvalidCraftsmanshipFeeException", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to مقدار {0} برای ویژگی با نوع {1} معتبر نمی‌باشد.
/// </summary>
public static string InvalidProductVariantValueException {
get {
return ResourceManager.GetString("InvalidProductVariantValueException", resourceCulture);
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More