2502cbbda2
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 8m44s
Payment Gateway: - Add PYMSPaymentService: IPaymentGatewayService via gRPC to PYMS microservice - Add ZarinPalPaymentService: direct ZarinPal integration (backup) - Register 'pyms' payment provider in DI ConfigureServices - Add PYMS proto files (pyms_transaction.proto, pyms_public_messages.proto) - Fix VerifyDiscountWalletCharge: pass 'OK' as status instead of Authority - Update appsettings: PaymentProvider=pyms, sandbox mode, merchant ID Blog System: - Add BlogCategory, BlogPost, BlogPostImage entities and CQRS - Add proto files and gRPC services for blog management - Add Mapster profiles for blog responses Content Management: - Add SitePage entity and CQRS for static pages - Add proto and gRPC service for site pages Image/File Management: - Add LocalFileManager with disk storage + base64 serving + FMS fallback - Add ImagePathResolverInterceptor for gRPC responses - Add ImageResolverService for explicit image resolution - Add UploadsController for public file serving with FMS fallback - Add PaymentCallbackController for discount order payment callbacks Database: - Add blog and content entity migrations - Remove ImagePath MaxLength constraints - Remove old FileManagementService (replaced by LocalFileManager)
99 lines
3.5 KiB
C#
99 lines
3.5 KiB
C#
using CMSMicroservice.Application.Common.FileManager;
|
|
using CMSMicroservice.Application.Common.Interfaces;
|
|
using CMSMicroservice.Domain.Entities.Blog;
|
|
using CMSMicroservice.Domain.Enums;
|
|
using MediatR;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace CMSMicroservice.Application.BlogPostCQ.Commands.CreateBlogPost;
|
|
|
|
public class CreateBlogPostCommandHandler : IRequestHandler<CreateBlogPostCommand, long>
|
|
{
|
|
private readonly IApplicationDbContext _context;
|
|
private readonly ICurrentUserService _currentUser;
|
|
private readonly IFileManager _fileManager;
|
|
private readonly ILogger<CreateBlogPostCommandHandler> _logger;
|
|
|
|
public CreateBlogPostCommandHandler(
|
|
IApplicationDbContext context,
|
|
ICurrentUserService currentUser,
|
|
IFileManager fileManager,
|
|
ILogger<CreateBlogPostCommandHandler> logger)
|
|
{
|
|
_context = context;
|
|
_currentUser = currentUser;
|
|
_fileManager = fileManager;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task<long> Handle(CreateBlogPostCommand request, CancellationToken cancellationToken)
|
|
{
|
|
var currentUserId = _currentUser.UserId;
|
|
if (string.IsNullOrEmpty(currentUserId) || !long.TryParse(currentUserId, out var authorUserId))
|
|
throw new UnauthorizedAccessException("کاربر احراز هویت نشده است");
|
|
|
|
var post = new BlogPost
|
|
{
|
|
Title = request.Title.Trim(),
|
|
Slug = string.IsNullOrWhiteSpace(request.Slug)
|
|
? $"post-{Guid.NewGuid():N}".Substring(0, 20)
|
|
: request.Slug.Trim().ToLower(),
|
|
Summary = request.Summary?.Trim(),
|
|
HtmlContent = request.HtmlContent,
|
|
FeaturedImagePath = request.FeaturedImagePath,
|
|
FeaturedImageThumbnailPath = request.FeaturedImageThumbnailPath,
|
|
Status = BlogPostStatus.Draft,
|
|
AuthorUserId = authorUserId,
|
|
IsFeatured = request.IsFeatured,
|
|
SortOrder = request.SortOrder,
|
|
ViewCount = 0
|
|
};
|
|
|
|
// آپلود تصویر شاخص (اگر فایل ارسال شده باشد)
|
|
if (request.ImageFileBytes is { Length: > 0 })
|
|
{
|
|
var result = await _fileManager.UploadImageAsync(
|
|
"Images/BlogPosts",
|
|
request.ImageFileBytes,
|
|
request.ImageFileMime ?? "image/jpeg",
|
|
request.ImageFileName,
|
|
cancellationToken);
|
|
|
|
post.FeaturedImagePath = result.Main.Path;
|
|
post.FeaturedImageThumbnailPath = result.Thumbnail.Path;
|
|
}
|
|
|
|
_context.BlogPosts.Add(post);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
|
|
// افزودن دستهبندیها
|
|
foreach (var categoryId in request.CategoryIds)
|
|
{
|
|
_context.BlogPostCategories.Add(new BlogPostCategory
|
|
{
|
|
BlogPostId = post.Id,
|
|
BlogCategoryId = categoryId
|
|
});
|
|
}
|
|
|
|
// افزودن تگها
|
|
foreach (var tagId in request.TagIds)
|
|
{
|
|
_context.BlogPostTags.Add(new BlogPostTag
|
|
{
|
|
BlogPostId = post.Id,
|
|
TagId = tagId
|
|
});
|
|
}
|
|
|
|
if (request.CategoryIds.Any() || request.TagIds.Any())
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
|
|
_logger.LogInformation(
|
|
"Blog post created. Id: {Id}, Title: {Title}, Author: {Author}",
|
|
post.Id, post.Title, authorUserId);
|
|
|
|
return post.Id;
|
|
}
|
|
}
|