feat: integrate PYMS payment gateway, add blog/sitepage/image services, local file manager
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 8m44s
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)
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
using CMSMicroservice.Domain.Common;
|
||||
|
||||
namespace CMSMicroservice.Domain.Entities.Blog;
|
||||
|
||||
/// <summary>
|
||||
/// دستهبندی مقالات بلاگ
|
||||
/// </summary>
|
||||
public class BlogCategory : BaseAuditableEntity
|
||||
{
|
||||
//عنوان دستهبندی
|
||||
public string Title { get; set; } = string.Empty;
|
||||
//نشانی یکتا
|
||||
public string Slug { get; set; } = string.Empty;
|
||||
//توضیحات
|
||||
public string? Description { get; set; }
|
||||
//نام آیکون Material
|
||||
public string? IconName { get; set; }
|
||||
//ترتیب نمایش
|
||||
public int SortOrder { get; set; }
|
||||
//فعال؟
|
||||
public bool IsActive { get; set; } = true;
|
||||
|
||||
//مقالات
|
||||
public virtual ICollection<BlogPostCategory> BlogPostCategories { get; set; } = new List<BlogPostCategory>();
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Domain.Entities.Blog;
|
||||
|
||||
/// <summary>
|
||||
/// مقاله بلاگ
|
||||
/// شامل عنوان، خلاصه، محتوای HTML، تصویر شاخص، وضعیت انتشار و آمار بازدید
|
||||
/// </summary>
|
||||
public class BlogPost : BaseAuditableEntity
|
||||
{
|
||||
//عنوان مقاله
|
||||
public string Title { get; set; } = string.Empty;
|
||||
//نشانی یکتا (slug)
|
||||
public string Slug { get; set; } = string.Empty;
|
||||
//خلاصه مقاله برای نمایش در کارتها
|
||||
public string? Summary { get; set; }
|
||||
//محتوای HTML مقاله
|
||||
public string HtmlContent { get; set; } = string.Empty;
|
||||
//مسیر تصویر شاخص
|
||||
public string? FeaturedImagePath { get; set; }
|
||||
//مسیر تامبنیل تصویر شاخص
|
||||
public string? FeaturedImageThumbnailPath { get; set; }
|
||||
//وضعیت مقاله
|
||||
public BlogPostStatus Status { get; set; } = BlogPostStatus.Draft;
|
||||
//زمان انتشار
|
||||
public DateTime? PublishedAt { get; set; }
|
||||
//زمانبندی انتشار خودکار
|
||||
public DateTime? ScheduledPublishAt { get; set; }
|
||||
//تعداد بازدید
|
||||
public int ViewCount { get; set; } = 0;
|
||||
//شناسه نویسنده
|
||||
public long AuthorUserId { get; set; }
|
||||
//نمایش در صفحه اول
|
||||
public bool IsFeatured { get; set; } = false;
|
||||
//ترتیب نمایش
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
//دستهبندیها
|
||||
public virtual ICollection<BlogPostCategory> BlogPostCategories { get; set; } = new List<BlogPostCategory>();
|
||||
//تگها
|
||||
public virtual ICollection<BlogPostTag> BlogPostTags { get; set; } = new List<BlogPostTag>();
|
||||
//تصاویر گالری
|
||||
public virtual ICollection<BlogPostImage> BlogPostImages { get; set; } = new List<BlogPostImage>();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using CMSMicroservice.Domain.Common;
|
||||
|
||||
namespace CMSMicroservice.Domain.Entities.Blog;
|
||||
|
||||
/// <summary>
|
||||
/// جدول واسط بین مقاله و دستهبندی (چند به چند)
|
||||
/// </summary>
|
||||
public class BlogPostCategory : BaseEntity
|
||||
{
|
||||
public long BlogPostId { get; set; }
|
||||
public long BlogCategoryId { get; set; }
|
||||
|
||||
public virtual BlogPost BlogPost { get; set; } = null!;
|
||||
public virtual BlogCategory BlogCategory { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using CMSMicroservice.Domain.Common;
|
||||
|
||||
namespace CMSMicroservice.Domain.Entities.Blog;
|
||||
|
||||
/// <summary>
|
||||
/// تصاویر گالری مقاله
|
||||
/// </summary>
|
||||
public class BlogPostImage : BaseAuditableEntity
|
||||
{
|
||||
public long BlogPostId { get; set; }
|
||||
//مسیر تصویر
|
||||
public string ImagePath { get; set; } = string.Empty;
|
||||
//مسیر تامبنیل
|
||||
public string ThumbnailPath { get; set; } = string.Empty;
|
||||
//متن جایگزین
|
||||
public string? AltText { get; set; }
|
||||
//عنوان تصویر
|
||||
public string? Caption { get; set; }
|
||||
//ترتیب نمایش
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
public virtual BlogPost BlogPost { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using CMSMicroservice.Domain.Common;
|
||||
|
||||
namespace CMSMicroservice.Domain.Entities.Blog;
|
||||
|
||||
/// <summary>
|
||||
/// جدول واسط بین مقاله و تگ (چند به چند)
|
||||
/// از Tag موجود استفاده مجدد میشود
|
||||
/// </summary>
|
||||
public class BlogPostTag : BaseEntity
|
||||
{
|
||||
public long BlogPostId { get; set; }
|
||||
public long TagId { get; set; }
|
||||
|
||||
public virtual BlogPost BlogPost { get; set; } = null!;
|
||||
public virtual Tag Tag { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using CMSMicroservice.Domain.Common;
|
||||
|
||||
namespace CMSMicroservice.Domain.Entities.Content;
|
||||
|
||||
/// <summary>
|
||||
/// صفحات دینامیک سایت (درباره ما، تماس با ما و ...)
|
||||
/// محتوای هر صفحه از طریق پنل ادمین قابل ویرایش است
|
||||
/// </summary>
|
||||
public class SitePage : BaseAuditableEntity
|
||||
{
|
||||
//کلید یکتا (about, contact, ...)
|
||||
public string PageKey { get; set; } = string.Empty;
|
||||
//عنوان صفحه
|
||||
public string Title { get; set; } = string.Empty;
|
||||
//توضیح متا برای SEO
|
||||
public string? MetaDescription { get; set; }
|
||||
//عنوان Hero
|
||||
public string? HeroTitle { get; set; }
|
||||
//زیرعنوان Hero
|
||||
public string? HeroSubtitle { get; set; }
|
||||
//مسیر تصویر Hero
|
||||
public string? HeroImagePath { get; set; }
|
||||
//فعال؟
|
||||
public bool IsActive { get; set; } = true;
|
||||
|
||||
//بخشهای صفحه
|
||||
public virtual ICollection<SitePageSection> Sections { get; set; } = new List<SitePageSection>();
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using CMSMicroservice.Domain.Common;
|
||||
|
||||
namespace CMSMicroservice.Domain.Entities.Content;
|
||||
|
||||
/// <summary>
|
||||
/// بخشهای یک صفحه دینامیک
|
||||
/// هر صفحه میتواند N بخش با ترتیب نمایش داشته باشد
|
||||
/// </summary>
|
||||
public class SitePageSection : BaseAuditableEntity
|
||||
{
|
||||
public long SitePageId { get; set; }
|
||||
//کلید بخش (mission, vision, team-member-1, ...)
|
||||
public string SectionKey { get; set; } = string.Empty;
|
||||
//عنوان بخش
|
||||
public string Title { get; set; } = string.Empty;
|
||||
//زیرعنوان
|
||||
public string? Subtitle { get; set; }
|
||||
//محتوای HTML
|
||||
public string? HtmlContent { get; set; }
|
||||
//نام آیکون Material
|
||||
public string? IconName { get; set; }
|
||||
//مسیر تصویر
|
||||
public string? ImagePath { get; set; }
|
||||
//مسیر تامبنیل
|
||||
public string? ImageThumbnailPath { get; set; }
|
||||
//ترتیب نمایش
|
||||
public int SortOrder { get; set; }
|
||||
//فعال؟
|
||||
public bool IsActive { get; set; } = true;
|
||||
//داده اضافی JSON (برای فیلدهای انعطافپذیر)
|
||||
public string? ExtraData { get; set; }
|
||||
|
||||
public virtual SitePage SitePage { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace CMSMicroservice.Domain.Enums;
|
||||
|
||||
public enum BlogPostStatus
|
||||
{
|
||||
Draft = 0,
|
||||
Published = 1,
|
||||
Scheduled = 2,
|
||||
Archived = 3
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
namespace CMSMicroservice.Domain.Events;
|
||||
public class CreateNewOtpTokenEvent : BaseEvent
|
||||
{
|
||||
public CreateNewOtpTokenEvent(OtpToken item, string plainCode)
|
||||
public CreateNewOtpTokenEvent(OtpToken item, string plainCode, string? signGuid = null)
|
||||
{
|
||||
Item = item;
|
||||
PlainCode = plainCode;
|
||||
SignGuid = signGuid;
|
||||
}
|
||||
|
||||
public OtpToken Item { get; }
|
||||
@@ -12,4 +13,8 @@ public class CreateNewOtpTokenEvent : BaseEvent
|
||||
/// کد OTP به صورت plain text برای ارسال SMS
|
||||
/// </summary>
|
||||
public string PlainCode { get; }
|
||||
/// <summary>
|
||||
/// شناسه GUID قرارداد (فقط برای امضای قرارداد)
|
||||
/// </summary>
|
||||
public string? SignGuid { get; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user