This commit is contained in:
masoodafar-web
2025-11-17 23:49:48 +03:30
parent 51d1f9a6f5
commit 78e461909f
31 changed files with 48296 additions and 7383 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,20 @@
namespace CMSMicroservice.Application.CategoryCQ.Commands.CreateNewCategory;
public record CreateNewCategoryCommand : IRequest<CreateNewCategoryResponseDto>
{
//نام لاتین
public string Name { get; init; }
//عنوان
public string Title { get; init; }
//توضیحات
public string? Description { get; init; }
//آدرس تصویر
public string? ImagePath { get; init; }
//شناسه والد
public long? ParentId { get; init; }
//فعال؟
public bool IsActive { get; init; }
//ترتیب نمایش
public int SortOrder { get; init; }
}

View File

@@ -0,0 +1,22 @@
using CMSMicroservice.Domain.Events;
namespace CMSMicroservice.Application.CategoryCQ.Commands.CreateNewCategory;
public class CreateNewCategoryCommandHandler : IRequestHandler<CreateNewCategoryCommand, CreateNewCategoryResponseDto>
{
private readonly IApplicationDbContext _context;
public CreateNewCategoryCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<CreateNewCategoryResponseDto> Handle(CreateNewCategoryCommand request,
CancellationToken cancellationToken)
{
var entity = request.Adapt<Category>();
await _context.Categories.AddAsync(entity, cancellationToken);
entity.AddDomainEvent(new CreateNewCategoryEvent(entity));
await _context.SaveChangesAsync(cancellationToken);
return entity.Adapt<CreateNewCategoryResponseDto>();
}
}

View File

@@ -0,0 +1,21 @@
namespace CMSMicroservice.Application.CategoryCQ.Commands.CreateNewCategory;
public class CreateNewCategoryCommandValidator : AbstractValidator<CreateNewCategoryCommand>
{
public CreateNewCategoryCommandValidator()
{
RuleFor(model => model.Name)
.NotEmpty();
RuleFor(model => model.Title)
.NotEmpty();
RuleFor(model => model.SortOrder)
.NotNull();
}
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
{
var result = await ValidateAsync(ValidationContext<CreateNewCategoryCommand>.CreateWithOptions((CreateNewCategoryCommand)model, x => x.IncludeProperties(propertyName)));
if (result.IsValid)
return Array.Empty<string>();
return result.Errors.Select(e => e.ErrorMessage);
};
}

View File

@@ -0,0 +1,8 @@
namespace CMSMicroservice.Application.CategoryCQ.Commands.CreateNewCategory;
public class CreateNewCategoryResponseDto
{
//شناسه
public long Id { get; set; }
}

View File

@@ -0,0 +1,8 @@
namespace CMSMicroservice.Application.CategoryCQ.Commands.DeleteCategory;
public record DeleteCategoryCommand : IRequest<Unit>
{
//شناسه
public long Id { get; init; }
}

View File

@@ -0,0 +1,23 @@
using CMSMicroservice.Domain.Events;
namespace CMSMicroservice.Application.CategoryCQ.Commands.DeleteCategory;
public class DeleteCategoryCommandHandler : IRequestHandler<DeleteCategoryCommand, Unit>
{
private readonly IApplicationDbContext _context;
public DeleteCategoryCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<Unit> Handle(DeleteCategoryCommand request, CancellationToken cancellationToken)
{
var entity = await _context.Categories
.FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(Category), request.Id);
entity.IsDeleted = true;
_context.Categories.Update(entity);
entity.AddDomainEvent(new DeleteCategoryEvent(entity));
await _context.SaveChangesAsync(cancellationToken);
return Unit.Value;
}
}

View File

@@ -0,0 +1,17 @@
namespace CMSMicroservice.Application.CategoryCQ.Commands.DeleteCategory;
public class DeleteCategoryCommandValidator : AbstractValidator<DeleteCategoryCommand>
{
public DeleteCategoryCommandValidator()
{
RuleFor(model => model.Id)
.NotNull();
}
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
{
var result = await ValidateAsync(ValidationContext<DeleteCategoryCommand>.CreateWithOptions((DeleteCategoryCommand)model, x => x.IncludeProperties(propertyName)));
if (result.IsValid)
return Array.Empty<string>();
return result.Errors.Select(e => e.ErrorMessage);
};
}

View File

@@ -0,0 +1,22 @@
namespace CMSMicroservice.Application.CategoryCQ.Commands.UpdateCategory;
public record UpdateCategoryCommand : IRequest<Unit>
{
//شناسه
public long Id { get; init; }
//نام لاتین
public string Name { get; init; }
//عنوان
public string Title { get; init; }
//توضیحات
public string? Description { get; init; }
//آدرس تصویر
public string? ImagePath { get; init; }
//شناسه والد
public long? ParentId { get; init; }
//فعال؟
public bool IsActive { get; init; }
//ترتیب نمایش
public int SortOrder { get; init; }
}

View File

@@ -0,0 +1,23 @@
using CMSMicroservice.Domain.Events;
namespace CMSMicroservice.Application.CategoryCQ.Commands.UpdateCategory;
public class UpdateCategoryCommandHandler : IRequestHandler<UpdateCategoryCommand, Unit>
{
private readonly IApplicationDbContext _context;
public UpdateCategoryCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<Unit> Handle(UpdateCategoryCommand request, CancellationToken cancellationToken)
{
var entity = await _context.Categories
.FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(Category), request.Id);
request.Adapt(entity);
_context.Categories.Update(entity);
entity.AddDomainEvent(new UpdateCategoryEvent(entity));
await _context.SaveChangesAsync(cancellationToken);
return Unit.Value;
}
}

View File

@@ -0,0 +1,23 @@
namespace CMSMicroservice.Application.CategoryCQ.Commands.UpdateCategory;
public class UpdateCategoryCommandValidator : AbstractValidator<UpdateCategoryCommand>
{
public UpdateCategoryCommandValidator()
{
RuleFor(model => model.Id)
.NotNull();
RuleFor(model => model.Name)
.NotEmpty();
RuleFor(model => model.Title)
.NotEmpty();
RuleFor(model => model.SortOrder)
.NotNull();
}
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
{
var result = await ValidateAsync(ValidationContext<UpdateCategoryCommand>.CreateWithOptions((UpdateCategoryCommand)model, x => x.IncludeProperties(propertyName)));
if (result.IsValid)
return Array.Empty<string>();
return result.Errors.Select(e => e.ErrorMessage);
};
}

View File

@@ -0,0 +1,22 @@
using CMSMicroservice.Domain.Events;
using Microsoft.Extensions.Logging;
namespace CMSMicroservice.Application.CategoryCQ.EventHandlers;
public class CreateNewCategoryEventHandler : INotificationHandler<CreateNewCategoryEvent>
{
private readonly ILogger<CreateNewCategoryEventHandler> _logger;
public CreateNewCategoryEventHandler(ILogger<CreateNewCategoryEventHandler> logger)
{
_logger = logger;
}
public Task Handle(CreateNewCategoryEvent notification, CancellationToken cancellationToken)
{
_logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name);
return Task.CompletedTask;
}
}

View File

@@ -0,0 +1,22 @@
using CMSMicroservice.Domain.Events;
using Microsoft.Extensions.Logging;
namespace CMSMicroservice.Application.CategoryCQ.EventHandlers;
public class DeleteCategoryEventHandler : INotificationHandler<DeleteCategoryEvent>
{
private readonly ILogger<DeleteCategoryEventHandler> _logger;
public DeleteCategoryEventHandler(ILogger<DeleteCategoryEventHandler> logger)
{
_logger = logger;
}
public Task Handle(DeleteCategoryEvent notification, CancellationToken cancellationToken)
{
_logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name);
return Task.CompletedTask;
}
}

View File

@@ -0,0 +1,22 @@
using CMSMicroservice.Domain.Events;
using Microsoft.Extensions.Logging;
namespace CMSMicroservice.Application.CategoryCQ.EventHandlers;
public class UpdateCategoryEventHandler : INotificationHandler<UpdateCategoryEvent>
{
private readonly ILogger<UpdateCategoryEventHandler> _logger;
public UpdateCategoryEventHandler(ILogger<UpdateCategoryEventHandler> logger)
{
_logger = logger;
}
public Task Handle(UpdateCategoryEvent notification, CancellationToken cancellationToken)
{
_logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name);
return Task.CompletedTask;
}
}

View File

@@ -0,0 +1,31 @@
namespace CMSMicroservice.Application.CategoryCQ.Queries.GetAllCategoryByFilter;
public record GetAllCategoryByFilterQuery : IRequest<GetAllCategoryByFilterResponseDto>
{
//موقعیت صفحه بندی
public PaginationState? PaginationState { get; init; }
//مرتب سازی بر اساس
public string? SortBy { get; init; }
//فیلتر
public GetAllCategoryByFilterFilter? Filter { get; init; }
}
public class GetAllCategoryByFilterFilter
{
//شناسه
public long? Id { get; set; }
//نام لاتین
public string? Name { get; set; }
//عنوان
public string? Title { get; set; }
//توضیحات
public string? Description { get; set; }
//آدرس تصویر
public string? ImagePath { get; set; }
//شناسه والد
public long? ParentId { get; set; }
//فعال؟
public bool? IsActive { get; set; }
//ترتیب نمایش
public int? SortOrder { get; set; }
}

View File

@@ -0,0 +1,38 @@
namespace CMSMicroservice.Application.CategoryCQ.Queries.GetAllCategoryByFilter;
public class GetAllCategoryByFilterQueryHandler : IRequestHandler<GetAllCategoryByFilterQuery, GetAllCategoryByFilterResponseDto>
{
private readonly IApplicationDbContext _context;
public GetAllCategoryByFilterQueryHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<GetAllCategoryByFilterResponseDto> Handle(GetAllCategoryByFilterQuery request, CancellationToken cancellationToken)
{
var query = _context.Categories
.ApplyOrder(sortBy: request.SortBy)
.AsNoTracking()
.AsQueryable();
if (request.Filter is not null)
{
query = query
.Where(x => request.Filter.Id == null || x.Id == request.Filter.Id)
.Where(x => request.Filter.Name == null || x.Name.Contains(request.Filter.Name))
.Where(x => request.Filter.Title == null || x.Title.Contains(request.Filter.Title))
.Where(x => request.Filter.Description == null || (x.Description != null && x.Description.Contains(request.Filter.Description)))
.Where(x => request.Filter.ImagePath == null || (x.ImagePath != null && x.ImagePath.Contains(request.Filter.ImagePath)))
.Where(x => request.Filter.ParentId == null || x.ParentId == request.Filter.ParentId)
.Where(x => request.Filter.IsActive == null || x.IsActive == request.Filter.IsActive)
.Where(x => request.Filter.SortOrder == null || x.SortOrder == request.Filter.SortOrder)
;
}
return new GetAllCategoryByFilterResponseDto
{
MetaData = await query.GetMetaData(request.PaginationState, cancellationToken),
Models = await query.PaginatedListAsync(paginationState: request.PaginationState)
.ProjectToType<GetAllCategoryByFilterResponseModel>().ToListAsync(cancellationToken)
};
}
}

View File

@@ -0,0 +1,15 @@
namespace CMSMicroservice.Application.CategoryCQ.Queries.GetAllCategoryByFilter;
public class GetAllCategoryByFilterQueryValidator : AbstractValidator<GetAllCategoryByFilterQuery>
{
public GetAllCategoryByFilterQueryValidator()
{
}
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
{
var result = await ValidateAsync(ValidationContext<GetAllCategoryByFilterQuery>.CreateWithOptions((GetAllCategoryByFilterQuery)model, x => x.IncludeProperties(propertyName)));
if (result.IsValid)
return Array.Empty<string>();
return result.Errors.Select(e => e.ErrorMessage);
};
}

View File

@@ -0,0 +1,29 @@
namespace CMSMicroservice.Application.CategoryCQ.Queries.GetAllCategoryByFilter;
public class GetAllCategoryByFilterResponseDto
{
//متادیتا
public MetaData MetaData { get; set; }
//مدل خروجی
public List<GetAllCategoryByFilterResponseModel>? Models { get; set; }
}
public class GetAllCategoryByFilterResponseModel
{
//شناسه
public long Id { get; set; }
//نام لاتین
public string Name { get; set; }
//عنوان
public string Title { get; set; }
//توضیحات
public string? Description { get; set; }
//آدرس تصویر
public string? ImagePath { get; set; }
//شناسه والد
public long? ParentId { get; set; }
//فعال؟
public bool IsActive { get; set; }
//ترتیب نمایش
public int SortOrder { get; set; }
}

View File

@@ -0,0 +1,8 @@
namespace CMSMicroservice.Application.CategoryCQ.Queries.GetCategory;
public record GetCategoryQuery : IRequest<GetCategoryResponseDto>
{
//شناسه
public long Id { get; init; }
}

View File

@@ -0,0 +1,23 @@
namespace CMSMicroservice.Application.CategoryCQ.Queries.GetCategory;
public class GetCategoryQueryHandler : IRequestHandler<GetCategoryQuery, GetCategoryResponseDto>
{
private readonly IApplicationDbContext _context;
public GetCategoryQueryHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<GetCategoryResponseDto> Handle(GetCategoryQuery request,
CancellationToken cancellationToken)
{
var response = await _context.Categories
.AsNoTracking()
.Where(x => x.Id == request.Id)
.ProjectToType<GetCategoryResponseDto>()
.FirstOrDefaultAsync(cancellationToken);
return response ?? throw new NotFoundException(nameof(Category), request.Id);
}
}

View File

@@ -0,0 +1,17 @@
namespace CMSMicroservice.Application.CategoryCQ.Queries.GetCategory;
public class GetCategoryQueryValidator : AbstractValidator<GetCategoryQuery>
{
public GetCategoryQueryValidator()
{
RuleFor(model => model.Id)
.NotNull();
}
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
{
var result = await ValidateAsync(ValidationContext<GetCategoryQuery>.CreateWithOptions((GetCategoryQuery)model, x => x.IncludeProperties(propertyName)));
if (result.IsValid)
return Array.Empty<string>();
return result.Errors.Select(e => e.ErrorMessage);
};
}

View File

@@ -0,0 +1,22 @@
namespace CMSMicroservice.Application.CategoryCQ.Queries.GetCategory;
public class GetCategoryResponseDto
{
//شناسه
public long Id { get; set; }
//نام لاتین
public string Name { get; set; }
//عنوان
public string Title { get; set; }
//توضیحات
public string? Description { get; set; }
//آدرس تصویر
public string? ImagePath { get; set; }
//شناسه والد
public long? ParentId { get; set; }
//فعال؟
public bool IsActive { get; set; }
//ترتیب نمایش
public int SortOrder { get; set; }
}

View File

@@ -4,6 +4,7 @@ public interface IApplicationDbContext
{ {
DbSet<UserAddress> UserAddresss { get; } DbSet<UserAddress> UserAddresss { get; }
DbSet<Package> Packages { get; } DbSet<Package> Packages { get; }
DbSet<Category> Categories { get; }
DbSet<Role> Roles { get; } DbSet<Role> Roles { get; }
DbSet<UserRole> UserRoles { get; } DbSet<UserRole> UserRoles { get; }
DbSet<UserWallet> UserWallets { get; } DbSet<UserWallet> UserWallets { get; }
@@ -20,4 +21,4 @@ public interface IApplicationDbContext
DbSet<Contract> Contracts { get; } DbSet<Contract> Contracts { get; }
DbSet<UserContract> UserContracts { get; } DbSet<UserContract> UserContracts { get; }
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default); Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
} }

View File

@@ -0,0 +1,11 @@
namespace CMSMicroservice.Application.Common.Mappings;
public class CategoryProfile : IRegister
{
void IRegister.Register(TypeAdapterConfig config)
{
//config.NewConfig<Source,Destination>()
// .Map(dest => dest.FullName, src => $"{src.Firstname} {src.Lastname}");
}
}

View File

@@ -0,0 +1,24 @@
namespace CMSMicroservice.Domain.Entities;
//دسته بندی
public class Category : BaseAuditableEntity
{
//نام لاتین
public string Name { get; set; }
//عنوان
public string Title { get; set; }
//توضیحات
public string? Description { get; set; }
//آدرس تصویر
public string? ImagePath { get; set; }
//شناسه والد
public long? ParentId { get; set; }
//Category Navigation Property
public virtual Category? Parent { get; set; }
//Category Collection Navigation Reference
public virtual ICollection<Category> Categories { get; set; }
//فعال؟
public bool IsActive { get; set; }
//ترتیب نمایش
public int SortOrder { get; set; }
}

View File

@@ -0,0 +1,11 @@
namespace CMSMicroservice.Domain.Events;
public class CreateNewCategoryEvent : BaseEvent
{
public CreateNewCategoryEvent(Category item)
{
Item = item;
}
public Category Item { get; }
}

View File

@@ -0,0 +1,11 @@
namespace CMSMicroservice.Domain.Events;
public class DeleteCategoryEvent : BaseEvent
{
public DeleteCategoryEvent(Category item)
{
Item = item;
}
public Category Item { get; }
}

View File

@@ -0,0 +1,11 @@
namespace CMSMicroservice.Domain.Events;
public class UpdateCategoryEvent : BaseEvent
{
public UpdateCategoryEvent(Category item)
{
Item = item;
}
public Category Item { get; }
}

View File

@@ -41,6 +41,7 @@ public class ApplicationDbContext : DbContext, IApplicationDbContext
} }
public DbSet<UserAddress> UserAddresss => Set<UserAddress>(); public DbSet<UserAddress> UserAddresss => Set<UserAddress>();
public DbSet<Package> Packages => Set<Package>(); public DbSet<Package> Packages => Set<Package>();
public DbSet<Category> Categories => Set<Category>();
public DbSet<Role> Roles => Set<Role>(); public DbSet<Role> Roles => Set<Role>();
public DbSet<UserRole> UserRoles => Set<UserRole>(); public DbSet<UserRole> UserRoles => Set<UserRole>();
public DbSet<UserWallet> UserWallets => Set<UserWallet>(); public DbSet<UserWallet> UserWallets => Set<UserWallet>();

View File

@@ -0,0 +1,30 @@
using CMSMicroservice.Domain.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace CMSMicroservice.Infrastructure.Persistence.Configurations;
public class CategoryConfiguration : IEntityTypeConfiguration<Category>
{
public void Configure(EntityTypeBuilder<Category> builder)
{
builder.HasQueryFilter(p => !p.IsDeleted);
builder.Ignore(entity => entity.DomainEvents);
builder.HasKey(entity => entity.Id);
builder.Property(entity => entity.Id).UseIdentityColumn();
builder.Property(entity => entity.Name).IsRequired(true);
builder.Property(entity => entity.Title).IsRequired(true);
builder.Property(entity => entity.Description).IsRequired(false);
builder.Property(entity => entity.ImagePath).IsRequired(false);
builder.Property(entity => entity.IsActive).IsRequired(true);
builder.Property(entity => entity.SortOrder).IsRequired(true);
builder
.HasOne(entity => entity.Parent)
.WithMany(entity => entity.Categories)
.HasForeignKey(entity => entity.ParentId)
.IsRequired(false);
}
}