Add validators and services for Product Galleries and Product Tags

- Implemented Create, Delete, Get, and Update validators for Product Galleries.
- Added Create, Delete, Get, and Update validators for Product Tags.
- Created service classes for handling Discount Categories, Discount Orders, Discount Products, Discount Shopping Cart, Product Categories, Product Galleries, and Product Tags.
- Each service class integrates with CQRS for command and query handling.
- Established mapping profiles for Product Galleries.
This commit is contained in:
masoodafar-web
2025-12-04 02:40:49 +03:30
parent 40d54d08fc
commit f0f48118e7
436 changed files with 33159 additions and 2005 deletions

View File

@@ -0,0 +1,51 @@
using CMSMicroservice.Domain.Enums;
using MediatR;
namespace CMSMicroservice.Application.PublicMessageCQ.Commands.CreatePublicMessage;
/// <summary>
/// دستور ایجاد پیام عمومی
/// Admin می‌تواند پیام عمومی برای نمایش در داشبورد کاربران ایجاد کند
/// </summary>
public class CreatePublicMessageCommand : IRequest<long>
{
/// <summary>
/// عنوان پیام (حداکثر 200 کاراکتر)
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// محتوای پیام (حداکثر 2000 کاراکتر)
/// </summary>
public string Content { get; set; } = string.Empty;
/// <summary>
/// نوع پیام
/// </summary>
public MessageType Type { get; set; }
/// <summary>
/// اولویت پیام
/// </summary>
public MessagePriority Priority { get; set; }
/// <summary>
/// تاریخ شروع نمایش
/// </summary>
public DateTime StartsAt { get; set; }
/// <summary>
/// تاریخ پایان نمایش
/// </summary>
public DateTime ExpiresAt { get; set; }
/// <summary>
/// لینک اختیاری
/// </summary>
public string? LinkUrl { get; set; }
/// <summary>
/// متن دکمه لینک
/// </summary>
public string? LinkText { get; set; }
}

View File

@@ -0,0 +1,67 @@
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Domain.Entities.Message;
using MediatR;
using Microsoft.Extensions.Logging;
namespace CMSMicroservice.Application.PublicMessageCQ.Commands.CreatePublicMessage;
public class CreatePublicMessageCommandHandler : IRequestHandler<CreatePublicMessageCommand, long>
{
private readonly IApplicationDbContext _context;
private readonly ICurrentUserService _currentUser;
private readonly ILogger<CreatePublicMessageCommandHandler> _logger;
public CreatePublicMessageCommandHandler(
IApplicationDbContext context,
ICurrentUserService currentUser,
ILogger<CreatePublicMessageCommandHandler> logger)
{
_context = context;
_currentUser = currentUser;
_logger = logger;
}
public async Task<long> Handle(CreatePublicMessageCommand request, CancellationToken cancellationToken)
{
// 1. بررسی Admin
var currentUserId = _currentUser.UserId;
if (string.IsNullOrEmpty(currentUserId))
{
throw new UnauthorizedAccessException("کاربر احراز هویت نشده است");
}
if (!long.TryParse(currentUserId, out var createdByUserId))
{
throw new UnauthorizedAccessException("شناسه کاربر نامعتبر است");
}
// 2. ایجاد PublicMessage
var message = new PublicMessage
{
Title = request.Title.Trim(),
Content = request.Content.Trim(),
Type = request.Type,
Priority = request.Priority,
IsActive = true,
StartsAt = request.StartsAt,
ExpiresAt = request.ExpiresAt,
CreatedByUserId = createdByUserId,
ViewCount = 0,
LinkUrl = request.LinkUrl?.Trim(),
LinkText = request.LinkText?.Trim()
};
_context.PublicMessages.Add(message);
await _context.SaveChangesAsync(cancellationToken);
_logger.LogInformation(
"Public message created successfully. Id: {Id}, Title: {Title}, Type: {Type}, CreatedBy: {CreatedBy}",
message.Id,
message.Title,
message.Type,
createdByUserId
);
return message.Id;
}
}

View File

@@ -0,0 +1,39 @@
using FluentValidation;
namespace CMSMicroservice.Application.PublicMessageCQ.Commands.CreatePublicMessage;
public class CreatePublicMessageCommandValidator : AbstractValidator<CreatePublicMessageCommand>
{
public CreatePublicMessageCommandValidator()
{
RuleFor(x => x.Title)
.NotEmpty().WithMessage("عنوان پیام الزامی است")
.MaximumLength(200).WithMessage("عنوان نمی‌تواند بیشتر از 200 کاراکتر باشد");
RuleFor(x => x.Content)
.NotEmpty().WithMessage("محتوای پیام الزامی است")
.MaximumLength(2000).WithMessage("محتوا نمی‌تواند بیشتر از 2000 کاراکتر باشد");
RuleFor(x => x.Type)
.IsInEnum().WithMessage("نوع پیام نامعتبر است");
RuleFor(x => x.Priority)
.IsInEnum().WithMessage("اولویت پیام نامعتبر است");
RuleFor(x => x.StartsAt)
.NotEmpty().WithMessage("تاریخ شروع الزامی است")
.LessThan(x => x.ExpiresAt).WithMessage("تاریخ شروع باید قبل از تاریخ پایان باشد");
RuleFor(x => x.ExpiresAt)
.NotEmpty().WithMessage("تاریخ پایان الزامی است")
.GreaterThan(DateTime.UtcNow).WithMessage("تاریخ پایان باید در آینده باشد");
RuleFor(x => x.LinkUrl)
.MaximumLength(500).WithMessage("لینک نمی‌تواند بیشتر از 500 کاراکتر باشد")
.When(x => !string.IsNullOrEmpty(x.LinkUrl));
RuleFor(x => x.LinkText)
.MaximumLength(100).WithMessage("متن لینک نمی‌تواند بیشتر از 100 کاراکتر باشد")
.When(x => !string.IsNullOrEmpty(x.LinkText));
}
}

View File

@@ -0,0 +1,15 @@
using MediatR;
namespace CMSMicroservice.Application.PublicMessageCQ.Commands.DeletePublicMessage;
/// <summary>
/// دستور حذف (soft delete) پیام عمومی
/// Admin می‌تواند پیام را حذف کند
/// </summary>
public class DeletePublicMessageCommand : IRequest<Unit>
{
/// <summary>
/// شناسه پیام
/// </summary>
public long Id { get; set; }
}

View File

@@ -0,0 +1,60 @@
using CMSMicroservice.Application.Common.Interfaces;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace CMSMicroservice.Application.PublicMessageCQ.Commands.DeletePublicMessage;
public class DeletePublicMessageCommandHandler : IRequestHandler<DeletePublicMessageCommand, Unit>
{
private readonly IApplicationDbContext _context;
private readonly ICurrentUserService _currentUser;
private readonly ILogger<DeletePublicMessageCommandHandler> _logger;
public DeletePublicMessageCommandHandler(
IApplicationDbContext context,
ICurrentUserService currentUser,
ILogger<DeletePublicMessageCommandHandler> logger)
{
_context = context;
_currentUser = currentUser;
_logger = logger;
}
public async Task<Unit> Handle(DeletePublicMessageCommand request, CancellationToken cancellationToken)
{
// 1. بررسی Admin
var currentUserId = _currentUser.UserId;
if (string.IsNullOrEmpty(currentUserId))
{
throw new UnauthorizedAccessException("کاربر احراز هویت نشده است");
}
if (!long.TryParse(currentUserId, out var userId))
{
throw new UnauthorizedAccessException("شناسه کاربر نامعتبر است");
}
// 2. بررسی وجود پیام
var message = await _context.PublicMessages
.FirstOrDefaultAsync(x => x.Id == request.Id && !x.IsDeleted, cancellationToken);
if (message == null)
{
throw new KeyNotFoundException($"پیام با شناسه {request.Id} یافت نشد");
}
// 3. Soft Delete
message.IsDeleted = true;
await _context.SaveChangesAsync(cancellationToken);
_logger.LogInformation(
"Public message deleted successfully. Id: {Id}, DeletedBy: {DeletedBy}",
message.Id,
userId
);
return Unit.Value;
}
}

View File

@@ -0,0 +1,61 @@
using CMSMicroservice.Domain.Enums;
using MediatR;
namespace CMSMicroservice.Application.PublicMessageCQ.Commands.UpdatePublicMessage;
/// <summary>
/// دستور ویرایش پیام عمومی
/// Admin می‌تواند پیام‌های منقضی نشده را ویرایش کند
/// </summary>
public class UpdatePublicMessageCommand : IRequest<Unit>
{
/// <summary>
/// شناسه پیام
/// </summary>
public long Id { get; set; }
/// <summary>
/// عنوان پیام (حداکثر 200 کاراکتر)
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// محتوای پیام (حداکثر 2000 کاراکتر)
/// </summary>
public string Content { get; set; } = string.Empty;
/// <summary>
/// نوع پیام
/// </summary>
public MessageType Type { get; set; }
/// <summary>
/// اولویت پیام
/// </summary>
public MessagePriority Priority { get; set; }
/// <summary>
/// وضعیت فعال/غیرفعال
/// </summary>
public bool IsActive { get; set; }
/// <summary>
/// تاریخ شروع نمایش
/// </summary>
public DateTime StartsAt { get; set; }
/// <summary>
/// تاریخ پایان نمایش
/// </summary>
public DateTime ExpiresAt { get; set; }
/// <summary>
/// لینک اختیاری
/// </summary>
public string? LinkUrl { get; set; }
/// <summary>
/// متن دکمه لینک
/// </summary>
public string? LinkText { get; set; }
}

View File

@@ -0,0 +1,68 @@
using CMSMicroservice.Application.Common.Interfaces;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace CMSMicroservice.Application.PublicMessageCQ.Commands.UpdatePublicMessage;
public class UpdatePublicMessageCommandHandler : IRequestHandler<UpdatePublicMessageCommand, Unit>
{
private readonly IApplicationDbContext _context;
private readonly ICurrentUserService _currentUser;
private readonly ILogger<UpdatePublicMessageCommandHandler> _logger;
public UpdatePublicMessageCommandHandler(
IApplicationDbContext context,
ICurrentUserService currentUser,
ILogger<UpdatePublicMessageCommandHandler> logger)
{
_context = context;
_currentUser = currentUser;
_logger = logger;
}
public async Task<Unit> Handle(UpdatePublicMessageCommand request, CancellationToken cancellationToken)
{
// 1. بررسی Admin
var currentUserId = _currentUser.UserId;
if (string.IsNullOrEmpty(currentUserId))
{
throw new UnauthorizedAccessException("کاربر احراز هویت نشده است");
}
if (!long.TryParse(currentUserId, out var userId))
{
throw new UnauthorizedAccessException("شناسه کاربر نامعتبر است");
}
// 2. بررسی وجود پیام
var message = await _context.PublicMessages
.FirstOrDefaultAsync(x => x.Id == request.Id && !x.IsDeleted, cancellationToken);
if (message == null)
{
throw new KeyNotFoundException($"پیام با شناسه {request.Id} یافت نشد");
}
// 3. به‌روزرسانی پیام
message.Title = request.Title.Trim();
message.Content = request.Content.Trim();
message.Type = request.Type;
message.Priority = request.Priority;
message.IsActive = request.IsActive;
message.StartsAt = request.StartsAt;
message.ExpiresAt = request.ExpiresAt;
message.LinkUrl = request.LinkUrl?.Trim();
message.LinkText = request.LinkText?.Trim();
await _context.SaveChangesAsync(cancellationToken);
_logger.LogInformation(
"Public message updated successfully. Id: {Id}, UpdatedBy: {UpdatedBy}",
message.Id,
userId
);
return Unit.Value;
}
}

View File

@@ -0,0 +1,41 @@
using FluentValidation;
namespace CMSMicroservice.Application.PublicMessageCQ.Commands.UpdatePublicMessage;
public class UpdatePublicMessageCommandValidator : AbstractValidator<UpdatePublicMessageCommand>
{
public UpdatePublicMessageCommandValidator()
{
RuleFor(x => x.Id)
.GreaterThan(0).WithMessage("شناسه پیام نامعتبر است");
RuleFor(x => x.Title)
.NotEmpty().WithMessage("عنوان پیام الزامی است")
.MaximumLength(200).WithMessage("عنوان نمی‌تواند بیشتر از 200 کاراکتر باشد");
RuleFor(x => x.Content)
.NotEmpty().WithMessage("محتوای پیام الزامی است")
.MaximumLength(2000).WithMessage("محتوا نمی‌تواند بیشتر از 2000 کاراکتر باشد");
RuleFor(x => x.Type)
.IsInEnum().WithMessage("نوع پیام نامعتبر است");
RuleFor(x => x.Priority)
.IsInEnum().WithMessage("اولویت پیام نامعتبر است");
RuleFor(x => x.StartsAt)
.NotEmpty().WithMessage("تاریخ شروع الزامی است")
.LessThan(x => x.ExpiresAt).WithMessage("تاریخ شروع باید قبل از تاریخ پایان باشد");
RuleFor(x => x.ExpiresAt)
.NotEmpty().WithMessage("تاریخ پایان الزامی است");
RuleFor(x => x.LinkUrl)
.MaximumLength(500).WithMessage("لینک نمی‌تواند بیشتر از 500 کاراکتر باشد")
.When(x => !string.IsNullOrEmpty(x.LinkUrl));
RuleFor(x => x.LinkText)
.MaximumLength(100).WithMessage("متن لینک نمی‌تواند بیشتر از 100 کاراکتر باشد")
.When(x => !string.IsNullOrEmpty(x.LinkText));
}
}