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)
117 lines
4.6 KiB
C#
117 lines
4.6 KiB
C#
using CMSMicroservice.Protobuf.Protos.BlogCategory;
|
|
using CMSMicroservice.WebApi.Common.Services;
|
|
using CMSMicroservice.Application.BlogCategoryCQ.Commands.CreateBlogCategory;
|
|
using CMSMicroservice.Application.BlogCategoryCQ.Commands.UpdateBlogCategory;
|
|
using CMSMicroservice.Application.BlogCategoryCQ.Commands.DeleteBlogCategory;
|
|
using CMSMicroservice.Application.BlogCategoryCQ.Queries.GetBlogCategory;
|
|
using CMSMicroservice.Application.BlogCategoryCQ.Queries.GetAllBlogCategories;
|
|
using CMSMicroservice.Application.BlogCategoryCQ.Queries.GetActiveBlogCategories;
|
|
using Google.Protobuf.WellKnownTypes;
|
|
using Grpc.Core;
|
|
using Mapster;
|
|
using MediatR;
|
|
using AppModels = CMSMicroservice.Application.Common.Models;
|
|
using ProtoMetaData = CMSMicroservice.Protobuf.Protos.MetaData;
|
|
|
|
namespace CMSMicroservice.WebApi.Services;
|
|
|
|
public class BlogCategoryService : BlogCategoryContract.BlogCategoryContractBase
|
|
{
|
|
private readonly ISender _sender;
|
|
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
|
|
|
public BlogCategoryService(ISender sender, IDispatchRequestToCQRS dispatchRequestToCQRS)
|
|
{
|
|
_sender = sender;
|
|
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
|
}
|
|
|
|
public override async Task<CreateBlogCategoryResponse> CreateBlogCategory(CreateBlogCategoryRequest request, ServerCallContext context)
|
|
{
|
|
return await _dispatchRequestToCQRS.Handle<CreateBlogCategoryRequest, CreateBlogCategoryCommand, CreateBlogCategoryResponse>(request, context);
|
|
}
|
|
|
|
public override async Task<Empty> UpdateBlogCategory(UpdateBlogCategoryRequest request, ServerCallContext context)
|
|
{
|
|
return await _dispatchRequestToCQRS.Handle<UpdateBlogCategoryRequest, UpdateBlogCategoryCommand>(request, context);
|
|
}
|
|
|
|
public override async Task<Empty> DeleteBlogCategory(DeleteBlogCategoryRequest request, ServerCallContext context)
|
|
{
|
|
return await _dispatchRequestToCQRS.Handle<DeleteBlogCategoryRequest, DeleteBlogCategoryCommand>(request, context);
|
|
}
|
|
|
|
public override async Task<GetBlogCategoryResponse> GetBlogCategory(GetBlogCategoryRequest request, ServerCallContext context)
|
|
{
|
|
var query = new GetBlogCategoryQuery { Id = request.Id };
|
|
var result = await _sender.Send(query, context.CancellationToken);
|
|
return MapCategoryToResponse(result);
|
|
}
|
|
|
|
public override async Task<GetAllBlogCategoriesResponse> GetAllBlogCategories(GetAllBlogCategoriesRequest request, ServerCallContext context)
|
|
{
|
|
var query = new GetAllBlogCategoriesQuery
|
|
{
|
|
PageNumber = request.PaginationState?.PageNumber ?? 1,
|
|
PageSize = request.PaginationState?.PageSize ?? 20,
|
|
SearchTerm = request.SortBy
|
|
};
|
|
|
|
var result = await _sender.Send(query, context.CancellationToken);
|
|
var response = new GetAllBlogCategoriesResponse
|
|
{
|
|
MetaData = result.MetaData.Adapt<ProtoMetaData>()
|
|
};
|
|
|
|
foreach (var item in result.Models)
|
|
response.Models.Add(MapToListItem(item));
|
|
|
|
return response;
|
|
}
|
|
|
|
public override async Task<GetActiveBlogCategoriesResponse> GetActiveBlogCategories(GetActiveBlogCategoriesRequest request, ServerCallContext context)
|
|
{
|
|
var query = new GetActiveBlogCategoriesQuery();
|
|
var result = await _sender.Send(query, context.CancellationToken);
|
|
|
|
var response = new GetActiveBlogCategoriesResponse();
|
|
foreach (var item in result)
|
|
response.Categories.Add(MapToListItem(item));
|
|
|
|
return response;
|
|
}
|
|
|
|
// ── Private Mapping Helpers ──
|
|
|
|
private static GetBlogCategoryResponse MapCategoryToResponse(BlogCategoryDto dto)
|
|
{
|
|
return new GetBlogCategoryResponse
|
|
{
|
|
Id = dto.Id,
|
|
Title = dto.Title ?? string.Empty,
|
|
Slug = dto.Slug ?? string.Empty,
|
|
Description = dto.Description,
|
|
IconName = dto.IconName,
|
|
SortOrder = dto.SortOrder,
|
|
IsActive = dto.IsActive,
|
|
PostCount = dto.PostCount,
|
|
Created = dto.Created != default ? Timestamp.FromDateTime(DateTime.SpecifyKind(dto.Created, DateTimeKind.Utc)) : null
|
|
};
|
|
}
|
|
|
|
private static BlogCategoryListItem MapToListItem(BlogCategoryDto dto)
|
|
{
|
|
return new BlogCategoryListItem
|
|
{
|
|
Id = dto.Id,
|
|
Title = dto.Title ?? string.Empty,
|
|
Slug = dto.Slug ?? string.Empty,
|
|
Description = dto.Description,
|
|
IconName = dto.IconName,
|
|
SortOrder = dto.SortOrder,
|
|
IsActive = dto.IsActive,
|
|
PostCount = dto.PostCount
|
|
};
|
|
}
|
|
}
|