feat: Add Protobuf definitions for Network Membership service
- Introduced `networkmembership.proto` with RPC methods for retrieving user network tree, statistics, and position. - Implemented HTTP annotations for gRPC transcoding in the service methods. - Added support for Google API annotations in `annotations.proto` and `http.proto`. - Created `ConfigureServices.cs` to register FluentValidation for the Protobuf services. - Updated project file to include necessary dependencies for gRPC and Protobuf.
This commit is contained in:
@@ -79,4 +79,9 @@ public class WeeklyBalanceItemDto
|
||||
/// آیا منقضی شده؟
|
||||
/// </summary>
|
||||
public bool IsExpired { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ شمسی
|
||||
/// </summary>
|
||||
public string DatePersian { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@ using CMSMicroservice.Protobuf.Protos.UserWallet;
|
||||
using CMSMicroservice.Protobuf.Protos.UserWalletChangeLog;
|
||||
using CMSMicroservice.Protobuf.Protos.ClubMembership;
|
||||
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountProduct;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountCategory;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountOrder;
|
||||
using PYMSMicroservice.Protobuf.Protos.Transaction;
|
||||
|
||||
namespace FrontOffice.BFF.Application.Common.Interfaces;
|
||||
@@ -49,6 +53,12 @@ public interface IApplicationContractContext
|
||||
// Network & Club System
|
||||
ClubMembershipContract.ClubMembershipContractClient ClubMemberships { get; }
|
||||
NetworkMembershipContract.NetworkMembershipContractClient NetworkMemberships { get; }
|
||||
|
||||
// Discount Shop System
|
||||
DiscountProductContract.DiscountProductContractClient DiscountProducts { get; }
|
||||
DiscountCategoryContract.DiscountCategoryContractClient DiscountCategories { get; }
|
||||
DiscountShoppingCartContract.DiscountShoppingCartContractClient DiscountCart { get; }
|
||||
DiscountOrderContract.DiscountOrderContractClient DiscountOrders { get; }
|
||||
#endregion
|
||||
|
||||
#region PYMS
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Commands.AddToDiscountCart;
|
||||
|
||||
/// <summary>
|
||||
/// افزودن محصول به سبد خرید تخفیفی
|
||||
/// </summary>
|
||||
public record AddToDiscountCartCommand : IRequest<AddToDiscountCartResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه محصول
|
||||
/// </summary>
|
||||
public long ProductId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// تعداد
|
||||
/// </summary>
|
||||
public int Count { get; init; } = 1;
|
||||
}
|
||||
|
||||
public class AddToDiscountCartResponseDto
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string Message { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
|
||||
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Commands.AddToDiscountCart;
|
||||
|
||||
public class AddToDiscountCartCommandHandler : IRequestHandler<AddToDiscountCartCommand, AddToDiscountCartResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
|
||||
public AddToDiscountCartCommandHandler(IApplicationContractContext context, ICurrentUserService currentUserService)
|
||||
{
|
||||
_context = context;
|
||||
_currentUserService = currentUserService;
|
||||
}
|
||||
|
||||
public async Task<AddToDiscountCartResponseDto> Handle(AddToDiscountCartCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var userId = _currentUserService.UserId ?? throw new UnauthorizedAccessException("User not authenticated");
|
||||
|
||||
var response = await _context.DiscountCart.AddToCartAsync(new AddToCartRequest
|
||||
{
|
||||
UserId = userId,
|
||||
ProductId = request.ProductId,
|
||||
Count = request.Count
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
return new AddToDiscountCartResponseDto
|
||||
{
|
||||
Success = response.Success,
|
||||
Message = response.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Commands.PlaceDiscountOrder;
|
||||
|
||||
/// <summary>
|
||||
/// ثبت سفارش از سبد خرید تخفیفی
|
||||
/// </summary>
|
||||
public record PlaceDiscountOrderCommand : IRequest<PlaceDiscountOrderResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه آدرس کاربر
|
||||
/// </summary>
|
||||
public long UserAddressId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// مقدار استفاده از موجودی تخفیف (اختیاری)
|
||||
/// </summary>
|
||||
public long DiscountBalanceToUse { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// توضیحات
|
||||
/// </summary>
|
||||
public string? Notes { get; init; }
|
||||
}
|
||||
|
||||
public class PlaceDiscountOrderResponseDto
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string Message { get; set; } = string.Empty;
|
||||
public long OrderId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ قابل پرداخت از درگاه
|
||||
/// </summary>
|
||||
public long GatewayAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// لینک پرداخت (اگر نیاز باشد)
|
||||
/// </summary>
|
||||
public string? PaymentUrl { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountOrder;
|
||||
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Commands.PlaceDiscountOrder;
|
||||
|
||||
public class PlaceDiscountOrderCommandHandler : IRequestHandler<PlaceDiscountOrderCommand, PlaceDiscountOrderResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
|
||||
public PlaceDiscountOrderCommandHandler(IApplicationContractContext context, ICurrentUserService currentUserService)
|
||||
{
|
||||
_context = context;
|
||||
_currentUserService = currentUserService;
|
||||
}
|
||||
|
||||
public async Task<PlaceDiscountOrderResponseDto> Handle(PlaceDiscountOrderCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var userId = _currentUserService.UserId ?? throw new UnauthorizedAccessException("User not authenticated");
|
||||
|
||||
var cmsRequest = new PlaceOrderRequest
|
||||
{
|
||||
UserId = userId,
|
||||
UserAddressId = request.UserAddressId,
|
||||
DiscountBalanceToUse = request.DiscountBalanceToUse
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(request.Notes))
|
||||
cmsRequest.Notes = request.Notes;
|
||||
|
||||
var response = await _context.DiscountOrders.PlaceOrderAsync(cmsRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return new PlaceDiscountOrderResponseDto
|
||||
{
|
||||
Success = response.Success,
|
||||
Message = response.Message,
|
||||
OrderId = response.OrderId,
|
||||
GatewayAmount = response.GatewayAmount,
|
||||
PaymentUrl = response.PaymentUrl
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Commands.RemoveFromDiscountCart;
|
||||
|
||||
/// <summary>
|
||||
/// حذف محصول از سبد خرید تخفیفی
|
||||
/// </summary>
|
||||
public record RemoveFromDiscountCartCommand : IRequest<RemoveFromDiscountCartResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه محصول
|
||||
/// </summary>
|
||||
public long ProductId { get; init; }
|
||||
}
|
||||
|
||||
public class RemoveFromDiscountCartResponseDto
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string Message { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
|
||||
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Commands.RemoveFromDiscountCart;
|
||||
|
||||
public class RemoveFromDiscountCartCommandHandler : IRequestHandler<RemoveFromDiscountCartCommand, RemoveFromDiscountCartResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
|
||||
public RemoveFromDiscountCartCommandHandler(IApplicationContractContext context, ICurrentUserService currentUserService)
|
||||
{
|
||||
_context = context;
|
||||
_currentUserService = currentUserService;
|
||||
}
|
||||
|
||||
public async Task<RemoveFromDiscountCartResponseDto> Handle(RemoveFromDiscountCartCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var userId = _currentUserService.UserId ?? throw new UnauthorizedAccessException("User not authenticated");
|
||||
|
||||
var response = await _context.DiscountCart.RemoveFromCartAsync(new RemoveFromCartRequest
|
||||
{
|
||||
UserId = userId,
|
||||
ProductId = request.ProductId
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
return new RemoveFromDiscountCartResponseDto
|
||||
{
|
||||
Success = response.Success,
|
||||
Message = response.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetDiscountCategories;
|
||||
|
||||
/// <summary>
|
||||
/// دریافت لیست دستهبندیهای فروشگاه تخفیفی
|
||||
/// </summary>
|
||||
public record GetDiscountCategoriesQuery : IRequest<GetDiscountCategoriesResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه دستهبندی والد (اختیاری)
|
||||
/// </summary>
|
||||
public long? ParentCategoryId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// فقط فعالها
|
||||
/// </summary>
|
||||
public bool OnlyActive { get; init; } = true;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountCategory;
|
||||
using CMSProto = CMSMicroservice.Protobuf.Protos.DiscountCategory;
|
||||
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetDiscountCategories;
|
||||
|
||||
public class GetDiscountCategoriesQueryHandler : IRequestHandler<GetDiscountCategoriesQuery, GetDiscountCategoriesResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetDiscountCategoriesQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetDiscountCategoriesResponseDto> Handle(GetDiscountCategoriesQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var cmsRequest = new GetDiscountCategoriesRequest();
|
||||
|
||||
if (request.ParentCategoryId.HasValue)
|
||||
cmsRequest.ParentCategoryId = request.ParentCategoryId.Value;
|
||||
|
||||
if (request.OnlyActive)
|
||||
cmsRequest.IsActive = true;
|
||||
|
||||
var response = await _context.DiscountCategories.GetDiscountCategoriesAsync(cmsRequest, cancellationToken: cancellationToken);
|
||||
|
||||
// Proto already returns tree structure with children
|
||||
var categories = response.Categories.Select(MapToDto).ToList();
|
||||
|
||||
return new GetDiscountCategoriesResponseDto
|
||||
{
|
||||
Categories = categories
|
||||
};
|
||||
}
|
||||
|
||||
private static DiscountCategoryDto MapToDto(CMSProto.DiscountCategoryDto model)
|
||||
{
|
||||
return new DiscountCategoryDto
|
||||
{
|
||||
Id = model.Id,
|
||||
Name = model.Name,
|
||||
Title = model.Title,
|
||||
Description = model.Description,
|
||||
ImagePath = model.ImagePath,
|
||||
ParentCategoryId = model.ParentCategoryId > 0 ? model.ParentCategoryId : null,
|
||||
SortOrder = model.SortOrder,
|
||||
IsActive = model.IsActive,
|
||||
Children = model.Children.Select(MapToDto).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetDiscountCategories;
|
||||
|
||||
public class GetDiscountCategoriesResponseDto
|
||||
{
|
||||
public List<DiscountCategoryDto> Categories { get; set; } = new();
|
||||
}
|
||||
|
||||
public class DiscountCategoryDto
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// نام
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// عنوان
|
||||
/// </summary>
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// توضیحات
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مسیر تصویر
|
||||
/// </summary>
|
||||
public string? ImagePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// شناسه والد
|
||||
/// </summary>
|
||||
public long? ParentCategoryId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ترتیب نمایش
|
||||
/// </summary>
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// فعال بودن
|
||||
/// </summary>
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// زیرمجموعهها
|
||||
/// </summary>
|
||||
public List<DiscountCategoryDto> Children { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetDiscountProducts;
|
||||
|
||||
/// <summary>
|
||||
/// دریافت لیست محصولات فروشگاه تخفیفی
|
||||
/// </summary>
|
||||
public record GetDiscountProductsQuery : IRequest<GetDiscountProductsResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه دستهبندی (اختیاری)
|
||||
/// </summary>
|
||||
public long? CategoryId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// شماره صفحه
|
||||
/// </summary>
|
||||
public int PageNumber { get; init; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// تعداد در هر صفحه
|
||||
/// </summary>
|
||||
public int PageSize { get; init; } = 20;
|
||||
|
||||
/// <summary>
|
||||
/// عبارت جستجو (اختیاری)
|
||||
/// </summary>
|
||||
public string? SearchTerm { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountProduct;
|
||||
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetDiscountProducts;
|
||||
|
||||
public class GetDiscountProductsQueryHandler : IRequestHandler<GetDiscountProductsQuery, GetDiscountProductsResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetDiscountProductsQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetDiscountProductsResponseDto> Handle(GetDiscountProductsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var cmsRequest = new GetDiscountProductsRequest
|
||||
{
|
||||
PageNumber = request.PageNumber,
|
||||
PageSize = request.PageSize
|
||||
};
|
||||
|
||||
if (request.CategoryId.HasValue)
|
||||
cmsRequest.CategoryId = request.CategoryId.Value;
|
||||
|
||||
if (!string.IsNullOrEmpty(request.SearchTerm))
|
||||
cmsRequest.SearchQuery = request.SearchTerm;
|
||||
|
||||
var response = await _context.DiscountProducts.GetDiscountProductsAsync(cmsRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return new GetDiscountProductsResponseDto
|
||||
{
|
||||
MetaData = new MetaData
|
||||
{
|
||||
TotalCount = response.MetaData?.TotalCount ?? 0
|
||||
},
|
||||
Products = response.Models.Select(p => new DiscountProductDto
|
||||
{
|
||||
Id = p.Id,
|
||||
Title = p.Title,
|
||||
ShortInformation = p.ShortInfomation,
|
||||
Price = p.Price,
|
||||
MaxDiscountPercent = p.MaxDiscountPercent,
|
||||
ImagePath = p.ImagePath,
|
||||
ThumbnailPath = p.ThumbnailPath,
|
||||
AvailableCount = p.RemainingCount,
|
||||
IsActive = p.IsActive
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetDiscountProducts;
|
||||
|
||||
public class GetDiscountProductsResponseDto
|
||||
{
|
||||
public MetaData MetaData { get; set; } = new();
|
||||
public List<DiscountProductDto> Products { get; set; } = new();
|
||||
}
|
||||
|
||||
public class DiscountProductDto
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه محصول
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// عنوان
|
||||
/// </summary>
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// توضیحات کوتاه
|
||||
/// </summary>
|
||||
public string ShortInformation { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// قیمت اصلی
|
||||
/// </summary>
|
||||
public long Price { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// حداکثر درصد تخفیف
|
||||
/// </summary>
|
||||
public int MaxDiscountPercent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// قیمت با تخفیف
|
||||
/// </summary>
|
||||
public long DiscountedPrice => Price - (Price * MaxDiscountPercent / 100);
|
||||
|
||||
/// <summary>
|
||||
/// مسیر تصویر
|
||||
/// </summary>
|
||||
public string ImagePath { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// مسیر تصویر کوچک
|
||||
/// </summary>
|
||||
public string ThumbnailPath { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// موجودی
|
||||
/// </summary>
|
||||
public int AvailableCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// فعال بودن
|
||||
/// </summary>
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// دستهبندیها
|
||||
/// </summary>
|
||||
public List<long> CategoryIds { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetMyDiscountCart;
|
||||
|
||||
/// <summary>
|
||||
/// دریافت سبد خرید فروشگاه تخفیفی کاربر جاری
|
||||
/// </summary>
|
||||
public record GetMyDiscountCartQuery : IRequest<GetMyDiscountCartResponseDto>;
|
||||
@@ -0,0 +1,42 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
|
||||
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetMyDiscountCart;
|
||||
|
||||
public class GetMyDiscountCartQueryHandler : IRequestHandler<GetMyDiscountCartQuery, GetMyDiscountCartResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
|
||||
public GetMyDiscountCartQueryHandler(IApplicationContractContext context, ICurrentUserService currentUserService)
|
||||
{
|
||||
_context = context;
|
||||
_currentUserService = currentUserService;
|
||||
}
|
||||
|
||||
public async Task<GetMyDiscountCartResponseDto> Handle(GetMyDiscountCartQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var userId = _currentUserService.UserId ?? throw new UnauthorizedAccessException("User not authenticated");
|
||||
|
||||
var response = await _context.DiscountCart.GetUserCartAsync(new GetUserCartRequest
|
||||
{
|
||||
UserId = userId
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
return new GetMyDiscountCartResponseDto
|
||||
{
|
||||
Items = response.Items.Select(i => new DiscountCartItemDto
|
||||
{
|
||||
Id = i.ProductId, // Use ProductId as unique identifier
|
||||
ProductId = i.ProductId,
|
||||
ProductTitle = i.ProductTitle,
|
||||
UnitPrice = i.UnitPrice,
|
||||
Count = i.Count,
|
||||
MaxDiscountPercent = i.MaxDiscountPercent,
|
||||
DiscountAmount = i.DiscountAmount,
|
||||
ThumbnailPath = i.ProductImagePath
|
||||
}).ToList(),
|
||||
TotalPrice = response.TotalPrice,
|
||||
TotalDiscountAmount = response.TotalDiscountAmount
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetMyDiscountCart;
|
||||
|
||||
public class GetMyDiscountCartResponseDto
|
||||
{
|
||||
/// <summary>
|
||||
/// آیتمهای سبد خرید
|
||||
/// </summary>
|
||||
public List<DiscountCartItemDto> Items { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// جمع کل قیمت (بدون تخفیف)
|
||||
/// </summary>
|
||||
public long TotalPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// جمع کل تخفیف
|
||||
/// </summary>
|
||||
public long TotalDiscountAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ قابل پرداخت
|
||||
/// </summary>
|
||||
public long PayableAmount => TotalPrice - TotalDiscountAmount;
|
||||
|
||||
/// <summary>
|
||||
/// تعداد کل آیتمها
|
||||
/// </summary>
|
||||
public int TotalItemCount => Items.Sum(i => i.Count);
|
||||
}
|
||||
|
||||
public class DiscountCartItemDto
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه آیتم سبد
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// شناسه محصول
|
||||
/// </summary>
|
||||
public long ProductId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// عنوان محصول
|
||||
/// </summary>
|
||||
public string ProductTitle { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// قیمت واحد
|
||||
/// </summary>
|
||||
public long UnitPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تعداد
|
||||
/// </summary>
|
||||
public int Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// درصد تخفیف
|
||||
/// </summary>
|
||||
public int MaxDiscountPercent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ تخفیف
|
||||
/// </summary>
|
||||
public long DiscountAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// قیمت کل ردیف
|
||||
/// </summary>
|
||||
public long TotalPrice => UnitPrice * Count;
|
||||
|
||||
/// <summary>
|
||||
/// مسیر تصویر
|
||||
/// </summary>
|
||||
public string ThumbnailPath { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetMyDiscountOrders;
|
||||
|
||||
/// <summary>
|
||||
/// دریافت سفارشات فروشگاه تخفیفی کاربر
|
||||
/// </summary>
|
||||
public record GetMyDiscountOrdersQuery : IRequest<GetMyDiscountOrdersResponseDto>
|
||||
{
|
||||
public int PageNumber { get; init; } = 1;
|
||||
public int PageSize { get; init; } = 20;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountOrder;
|
||||
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetMyDiscountOrders;
|
||||
|
||||
public class GetMyDiscountOrdersQueryHandler : IRequestHandler<GetMyDiscountOrdersQuery, GetMyDiscountOrdersResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
|
||||
public GetMyDiscountOrdersQueryHandler(IApplicationContractContext context, ICurrentUserService currentUserService)
|
||||
{
|
||||
_context = context;
|
||||
_currentUserService = currentUserService;
|
||||
}
|
||||
|
||||
public async Task<GetMyDiscountOrdersResponseDto> Handle(GetMyDiscountOrdersQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var userId = _currentUserService.UserId ?? throw new UnauthorizedAccessException("User not authenticated");
|
||||
|
||||
var response = await _context.DiscountOrders.GetUserOrdersAsync(new GetUserOrdersRequest
|
||||
{
|
||||
UserId = userId,
|
||||
PageNumber = request.PageNumber,
|
||||
PageSize = request.PageSize
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
return new GetMyDiscountOrdersResponseDto
|
||||
{
|
||||
MetaData = new MetaData
|
||||
{
|
||||
TotalCount = response.MetaData?.TotalCount ?? 0
|
||||
},
|
||||
Orders = response.Models.Select(o => new DiscountOrderDto
|
||||
{
|
||||
Id = o.Id,
|
||||
OrderNumber = o.OrderNumber,
|
||||
Status = MapStatus((int)o.DeliveryStatus),
|
||||
StatusColor = GetStatusColor((int)o.DeliveryStatus),
|
||||
TotalAmount = o.TotalPrice,
|
||||
DiscountUsed = o.DiscountBalanceUsed,
|
||||
GatewayPaid = o.GatewayAmount,
|
||||
CreatedAt = o.Created?.ToDateTime() ?? DateTime.UtcNow,
|
||||
CreatedAtPersian = FormatPersianDate(o.Created?.ToDateTime())
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
private static string MapStatus(int status)
|
||||
{
|
||||
return status switch
|
||||
{
|
||||
0 => "در انتظار پرداخت",
|
||||
1 => "در حال پردازش",
|
||||
2 => "ارسال شده",
|
||||
3 => "تحویل داده شده",
|
||||
4 => "لغو شده",
|
||||
_ => "نامشخص"
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetStatusColor(int status)
|
||||
{
|
||||
return status switch
|
||||
{
|
||||
0 => "warning",
|
||||
1 => "primary",
|
||||
2 => "info",
|
||||
3 => "success",
|
||||
4 => "danger",
|
||||
_ => "secondary"
|
||||
};
|
||||
}
|
||||
|
||||
private static string FormatPersianDate(DateTime? date)
|
||||
{
|
||||
if (!date.HasValue) return string.Empty;
|
||||
// TODO: استفاده از PersianCalendar
|
||||
return date.Value.ToString("yyyy/MM/dd HH:mm");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
namespace FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetMyDiscountOrders;
|
||||
|
||||
public class GetMyDiscountOrdersResponseDto
|
||||
{
|
||||
public MetaData MetaData { get; set; } = new();
|
||||
public List<DiscountOrderDto> Orders { get; set; } = new();
|
||||
}
|
||||
|
||||
public class DiscountOrderDto
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه سفارش
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// شماره سفارش
|
||||
/// </summary>
|
||||
public string OrderNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// وضعیت
|
||||
/// </summary>
|
||||
public string Status { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// رنگ وضعیت
|
||||
/// </summary>
|
||||
public string StatusColor { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// جمع کل
|
||||
/// </summary>
|
||||
public long TotalAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تخفیف استفاده شده
|
||||
/// </summary>
|
||||
public long DiscountUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ پرداخت شده از درگاه
|
||||
/// </summary>
|
||||
public long GatewayPaid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ ثبت
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ شمسی
|
||||
/// </summary>
|
||||
public string CreatedAtPersian { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkPosition;
|
||||
|
||||
public record GetMyNetworkPositionQuery : IRequest<GetMyNetworkPositionResponseDto>;
|
||||
@@ -0,0 +1,44 @@
|
||||
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
|
||||
|
||||
namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkPosition;
|
||||
|
||||
public class GetMyNetworkPositionQueryHandler : IRequestHandler<GetMyNetworkPositionQuery, GetMyNetworkPositionResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
|
||||
public GetMyNetworkPositionQueryHandler(
|
||||
IApplicationContractContext context,
|
||||
ICurrentUserService currentUserService)
|
||||
{
|
||||
_context = context;
|
||||
_currentUserService = currentUserService;
|
||||
}
|
||||
|
||||
public async Task<GetMyNetworkPositionResponseDto> Handle(GetMyNetworkPositionQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var userId = _currentUserService.UserId ?? throw new UnauthorizedAccessException("User not authenticated");
|
||||
|
||||
var response = await _context.NetworkMemberships.GetUserNetworkAsync(
|
||||
new GetUserNetworkRequest { UserId = userId },
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return new GetMyNetworkPositionResponseDto
|
||||
{
|
||||
UserId = response.UserId,
|
||||
ParentId = response.ParentId ?? 0,
|
||||
ParentName = response.ParentName ?? string.Empty,
|
||||
Position = response.NetworkLeg switch
|
||||
{
|
||||
0 => "Left",
|
||||
1 => "Right",
|
||||
_ => "Root"
|
||||
},
|
||||
Level = response.NetworkLevel,
|
||||
ReferralCode = response.ReferralCode ?? string.Empty,
|
||||
JoinedAt = response.JoinedAt?.ToDateTime() ?? DateTime.UtcNow,
|
||||
HasLeftChild = response.LeftChildId.HasValue,
|
||||
HasRightChild = response.RightChildId.HasValue
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkPosition;
|
||||
|
||||
public class GetMyNetworkPositionResponseDto
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه کاربر
|
||||
/// </summary>
|
||||
public long UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// شناسه والد
|
||||
/// </summary>
|
||||
public long ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// نام والد
|
||||
/// </summary>
|
||||
public string ParentName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// موقعیت در درخت (Left/Right)
|
||||
/// </summary>
|
||||
public string Position { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// سطح در درخت
|
||||
/// </summary>
|
||||
public int Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// کد معرف
|
||||
/// </summary>
|
||||
public string ReferralCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ عضویت
|
||||
/// </summary>
|
||||
public DateTime JoinedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// آیا فرزند چپ دارد؟
|
||||
/// </summary>
|
||||
public bool HasLeftChild { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// آیا فرزند راست دارد؟
|
||||
/// </summary>
|
||||
public bool HasRightChild { get; set; }
|
||||
}
|
||||
@@ -16,6 +16,10 @@ using CMSMicroservice.Protobuf.Protos.UserWallet;
|
||||
using CMSMicroservice.Protobuf.Protos.UserWalletChangeLog;
|
||||
using CMSMicroservice.Protobuf.Protos.ClubMembership;
|
||||
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountProduct;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountCategory;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountOrder;
|
||||
using FrontOffice.BFF.Application.Common.Interfaces;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using PYMSMicroservice.Protobuf.Protos.Transaction;
|
||||
@@ -76,6 +80,12 @@ public class ApplicationContractContext : IApplicationContractContext
|
||||
// Network & Club System
|
||||
public ClubMembershipContract.ClubMembershipContractClient ClubMemberships => GetService<ClubMembershipContract.ClubMembershipContractClient>();
|
||||
public NetworkMembershipContract.NetworkMembershipContractClient NetworkMemberships => GetService<NetworkMembershipContract.NetworkMembershipContractClient>();
|
||||
|
||||
// Discount Shop System
|
||||
public DiscountProductContract.DiscountProductContractClient DiscountProducts => GetService<DiscountProductContract.DiscountProductContractClient>();
|
||||
public DiscountCategoryContract.DiscountCategoryContractClient DiscountCategories => GetService<DiscountCategoryContract.DiscountCategoryContractClient>();
|
||||
public DiscountShoppingCartContract.DiscountShoppingCartContractClient DiscountCart => GetService<DiscountShoppingCartContract.DiscountShoppingCartContractClient>();
|
||||
public DiscountOrderContract.DiscountOrderContractClient DiscountOrders => GetService<DiscountOrderContract.DiscountOrderContractClient>();
|
||||
#endregion
|
||||
|
||||
#region PYMS
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
using FrontOffice.BFF.Application.ClubMembershipCQ.Queries.GetMyClubMembership;
|
||||
using FrontOffice.BFF.Application.ClubMembershipCQ.Commands.ActivateMyClubMembership;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using ProtoDto = FrontOffice.BFF.ClubMembership.Protobuf.Protos.ClubMembership;
|
||||
|
||||
namespace FrontOffice.BFF.WebApi.Common.Mappings;
|
||||
|
||||
public class ClubMembershipProfile : IRegister
|
||||
{
|
||||
void IRegister.Register(TypeAdapterConfig config)
|
||||
{
|
||||
// Request -> Command mappings
|
||||
config.NewConfig<ProtoDto.ActivateMyClubMembershipRequest, ActivateMyClubMembershipCommand>()
|
||||
.Map(dest => dest.PackageId, src => src.PackageId)
|
||||
.Map(dest => dest.ActivationCode, src => src.ActivationCode)
|
||||
.Map(dest => dest.DurationMonths, src => src.DurationMonths > 0 ? src.DurationMonths : 12);
|
||||
|
||||
// Response mappings
|
||||
config.NewConfig<GetMyClubMembershipResponseDto, ProtoDto.GetMyClubMembershipResponse>()
|
||||
.Map(dest => dest.UserId, src => src.UserId)
|
||||
.Map(dest => dest.PackageId, src => src.PackageId)
|
||||
.Map(dest => dest.PackageName, src => src.PackageName)
|
||||
.Map(dest => dest.ActivationCode, src => src.ActivationCode)
|
||||
.Map(dest => dest.IsActive, src => src.IsActive)
|
||||
.Map(dest => dest.ActivationDate, src => src.ActivationDate.HasValue
|
||||
? Timestamp.FromDateTime(DateTime.SpecifyKind(src.ActivationDate.Value, DateTimeKind.Utc))
|
||||
: null)
|
||||
.Map(dest => dest.ExpirationDate, src => src.ExpirationDate.HasValue
|
||||
? Timestamp.FromDateTime(DateTime.SpecifyKind(src.ExpirationDate.Value, DateTimeKind.Utc))
|
||||
: null)
|
||||
.Map(dest => dest.Status, src => src.Status)
|
||||
.Map(dest => dest.DaysRemaining, src => src.DaysRemaining)
|
||||
.Map(dest => dest.IsTrialPeriod, src => src.IsTrialPeriod);
|
||||
|
||||
config.NewConfig<ActivateMyClubMembershipResponseDto, ProtoDto.ActivateMyClubMembershipResponse>()
|
||||
.Map(dest => dest.Success, src => src.Success)
|
||||
.Map(dest => dest.Message, src => src.Message)
|
||||
.Map(dest => dest.ActivationDate, src => Timestamp.FromDateTime(DateTime.SpecifyKind(src.ActivationDate, DateTimeKind.Utc)))
|
||||
.Map(dest => dest.ExpirationDate, src => Timestamp.FromDateTime(DateTime.SpecifyKind(src.ExpirationDate, DateTimeKind.Utc)))
|
||||
.Map(dest => dest.AmountPaid, src => src.AmountPaid);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
|
||||
using FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyWeeklyBalances;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using ProtoDto = FrontOffice.BFF.Commission.Protobuf.Protos.Commission;
|
||||
|
||||
namespace FrontOffice.BFF.WebApi.Common.Mappings;
|
||||
|
||||
public class CommissionProfile : IRegister
|
||||
{
|
||||
void IRegister.Register(TypeAdapterConfig config)
|
||||
{
|
||||
// Request -> Query mappings
|
||||
config.NewConfig<ProtoDto.GetMyCommissionPayoutsRequest, GetMyCommissionPayoutsQuery>()
|
||||
.Map(dest => dest.PageNumber, src => src.PageNumber)
|
||||
.Map(dest => dest.PageSize, src => src.PageSize)
|
||||
.Map(dest => dest.WeekNumber, src => src.WeekNumber)
|
||||
.Map(dest => dest.Status, src => src.Status);
|
||||
|
||||
config.NewConfig<ProtoDto.GetMyWeeklyBalancesRequest, GetMyWeeklyBalancesQuery>()
|
||||
.Map(dest => dest.PageNumber, src => src.PageNumber)
|
||||
.Map(dest => dest.PageSize, src => src.PageSize)
|
||||
.Map(dest => dest.WeekNumber, src => src.WeekNumber)
|
||||
.Map(dest => dest.OnlyActive, src => src.OnlyActive);
|
||||
|
||||
// Response mappings
|
||||
config.NewConfig<GetMyCommissionPayoutsResponseDto, ProtoDto.GetMyCommissionPayoutsResponse>()
|
||||
.Map(dest => dest.MetaData, src => new ProtoDto.MetaData { TotalCount = src.TotalCount })
|
||||
.Map(dest => dest.Payouts, src => src.Payouts);
|
||||
|
||||
config.NewConfig<CommissionPayoutDto, ProtoDto.CommissionPayoutModel>()
|
||||
.Map(dest => dest.Id, src => src.Id)
|
||||
.Map(dest => dest.WeekNumber, src => src.WeekNumber)
|
||||
.Map(dest => dest.WeekLabel, src => src.WeekLabel)
|
||||
.Map(dest => dest.BalancesEarned, src => src.BalancesEarned)
|
||||
.Map(dest => dest.TotalAmount, src => src.TotalAmount)
|
||||
.Map(dest => dest.AmountFormatted, src => src.AmountFormatted)
|
||||
.Map(dest => dest.Status, src => src.Status)
|
||||
.Map(dest => dest.StatusBadgeColor, src => src.StatusBadgeColor)
|
||||
.Map(dest => dest.CalculatedDate, src => Timestamp.FromDateTime(DateTime.SpecifyKind(src.CalculatedDate, DateTimeKind.Utc)))
|
||||
.Map(dest => dest.DatePersian, src => src.DatePersian);
|
||||
|
||||
config.NewConfig<GetMyWeeklyBalancesResponseDto, ProtoDto.GetMyWeeklyBalancesResponse>()
|
||||
.Map(dest => dest.MetaData, src => new ProtoDto.MetaData { TotalCount = src.TotalCount })
|
||||
.Map(dest => dest.Balances, src => src.Balances)
|
||||
.Map(dest => dest.TotalLeftBalances, src => src.TotalLeftBalances)
|
||||
.Map(dest => dest.TotalRightBalances, src => src.TotalRightBalances)
|
||||
.Map(dest => dest.WeakerLeg, src => src.WeakerLeg);
|
||||
|
||||
config.NewConfig<WeeklyBalanceItemDto, ProtoDto.WeeklyBalanceModel>()
|
||||
.Map(dest => dest.Id, src => src.Id)
|
||||
.Map(dest => dest.WeekNumber, src => src.WeekNumber)
|
||||
.Map(dest => dest.LeftLegBalances, src => src.LeftLegBalances)
|
||||
.Map(dest => dest.RightLegBalances, src => src.RightLegBalances)
|
||||
.Map(dest => dest.TotalBalances, src => src.TotalBalances)
|
||||
.Map(dest => dest.WeeklyPoolContribution, src => src.WeeklyPoolContribution)
|
||||
.Map(dest => dest.IsExpired, src => src.IsExpired)
|
||||
.Map(dest => dest.DatePersian, src => src.DatePersian);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetDiscountProducts;
|
||||
using FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetDiscountCategories;
|
||||
using FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetMyDiscountCart;
|
||||
using FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetMyDiscountOrders;
|
||||
using FrontOffice.BFF.Application.DiscountShopCQ.Commands.AddToDiscountCart;
|
||||
using FrontOffice.BFF.Application.DiscountShopCQ.Commands.RemoveFromDiscountCart;
|
||||
using FrontOffice.BFF.Application.DiscountShopCQ.Commands.PlaceDiscountOrder;
|
||||
using ProtoDto = FrontOffice.BFF.DiscountShop.Protobuf.Protos.DiscountShop;
|
||||
|
||||
namespace FrontOffice.BFF.WebApi.Common.Mappings;
|
||||
|
||||
public class DiscountShopProfile : IRegister
|
||||
{
|
||||
void IRegister.Register(TypeAdapterConfig config)
|
||||
{
|
||||
// Request -> Query/Command mappings
|
||||
config.NewConfig<ProtoDto.GetDiscountProductsRequest, GetDiscountProductsQuery>()
|
||||
.Map(dest => dest.PageNumber, src => src.PageNumber)
|
||||
.Map(dest => dest.PageSize, src => src.PageSize)
|
||||
.Map(dest => dest.SearchTerm, src => src.SearchTerm)
|
||||
.Map(dest => dest.CategoryId, src => src.CategoryId);
|
||||
|
||||
config.NewConfig<ProtoDto.GetDiscountCategoriesRequest, GetDiscountCategoriesQuery>()
|
||||
.Map(dest => dest.ParentCategoryId, src => src.ParentCategoryId)
|
||||
.Map(dest => dest.OnlyActive, src => src.OnlyActive);
|
||||
|
||||
config.NewConfig<ProtoDto.GetMyDiscountOrdersRequest, GetMyDiscountOrdersQuery>()
|
||||
.Map(dest => dest.PageNumber, src => src.PageNumber)
|
||||
.Map(dest => dest.PageSize, src => src.PageSize);
|
||||
|
||||
config.NewConfig<ProtoDto.AddToDiscountCartRequest, AddToDiscountCartCommand>()
|
||||
.Map(dest => dest.ProductId, src => src.ProductId)
|
||||
.Map(dest => dest.Count, src => src.Count);
|
||||
|
||||
config.NewConfig<ProtoDto.RemoveFromDiscountCartRequest, RemoveFromDiscountCartCommand>()
|
||||
.Map(dest => dest.ProductId, src => src.ProductId);
|
||||
|
||||
config.NewConfig<ProtoDto.PlaceDiscountOrderRequest, PlaceDiscountOrderCommand>()
|
||||
.Map(dest => dest.UserAddressId, src => src.UserAddressId)
|
||||
.Map(dest => dest.DiscountBalanceToUse, src => src.DiscountBalanceToUse)
|
||||
.Map(dest => dest.Notes, src => src.Notes);
|
||||
|
||||
// Response mappings
|
||||
config.NewConfig<GetDiscountProductsResponseDto, ProtoDto.GetDiscountProductsResponse>()
|
||||
.Map(dest => dest.MetaData, src => new ProtoDto.MetaData { TotalCount = src.MetaData.TotalCount })
|
||||
.Map(dest => dest.Products, src => src.Products);
|
||||
|
||||
config.NewConfig<DiscountProductDto, ProtoDto.DiscountProductModel>()
|
||||
.Map(dest => dest.Id, src => src.Id)
|
||||
.Map(dest => dest.Title, src => src.Title)
|
||||
.Map(dest => dest.Description, src => src.ShortInformation)
|
||||
.Map(dest => dest.ImagePath, src => src.ImagePath)
|
||||
.Map(dest => dest.OriginalPrice, src => src.Price)
|
||||
.Map(dest => dest.DiscountedPrice, src => src.DiscountedPrice)
|
||||
.Map(dest => dest.DiscountPercent, src => src.MaxDiscountPercent)
|
||||
.Map(dest => dest.RemainingCount, src => src.AvailableCount)
|
||||
.Map(dest => dest.IsAvailable, src => src.IsActive);
|
||||
|
||||
config.NewConfig<GetDiscountCategoriesResponseDto, ProtoDto.GetDiscountCategoriesResponse>()
|
||||
.Map(dest => dest.Categories, src => src.Categories);
|
||||
|
||||
config.NewConfig<DiscountCategoryDto, ProtoDto.DiscountCategoryModel>()
|
||||
.Map(dest => dest.Id, src => src.Id)
|
||||
.Map(dest => dest.Title, src => src.Title)
|
||||
.Map(dest => dest.ParentId, src => src.ParentCategoryId)
|
||||
.Map(dest => dest.IconPath, src => src.ImagePath)
|
||||
.Map(dest => dest.SortOrder, src => src.SortOrder)
|
||||
.Map(dest => dest.Children, src => src.Children);
|
||||
|
||||
config.NewConfig<GetMyDiscountCartResponseDto, ProtoDto.GetMyDiscountCartResponse>()
|
||||
.Map(dest => dest.Items, src => src.Items)
|
||||
.Map(dest => dest.TotalPrice, src => src.TotalPrice)
|
||||
.Map(dest => dest.TotalDiscountAmount, src => src.TotalDiscountAmount);
|
||||
|
||||
config.NewConfig<DiscountCartItemDto, ProtoDto.DiscountCartItemModel>()
|
||||
.Map(dest => dest.ProductId, src => src.ProductId)
|
||||
.Map(dest => dest.ProductTitle, src => src.ProductTitle)
|
||||
.Map(dest => dest.ProductImagePath, src => src.ThumbnailPath)
|
||||
.Map(dest => dest.UnitPrice, src => src.UnitPrice)
|
||||
.Map(dest => dest.Count, src => src.Count)
|
||||
.Map(dest => dest.TotalPrice, src => src.TotalPrice);
|
||||
|
||||
config.NewConfig<GetMyDiscountOrdersResponseDto, ProtoDto.GetMyDiscountOrdersResponse>()
|
||||
.Map(dest => dest.MetaData, src => new ProtoDto.MetaData { TotalCount = src.MetaData.TotalCount })
|
||||
.Map(dest => dest.Orders, src => src.Orders);
|
||||
|
||||
config.NewConfig<DiscountOrderDto, ProtoDto.DiscountOrderModel>()
|
||||
.Map(dest => dest.Id, src => src.Id)
|
||||
.Map(dest => dest.OrderNumber, src => src.OrderNumber)
|
||||
.Map(dest => dest.Status, src => src.Status)
|
||||
.Map(dest => dest.StatusColor, src => src.StatusColor)
|
||||
.Map(dest => dest.TotalAmount, src => src.TotalAmount)
|
||||
.Map(dest => dest.DiscountUsed, src => src.DiscountUsed)
|
||||
.Map(dest => dest.GatewayPaid, src => src.GatewayPaid)
|
||||
.Map(dest => dest.CreatedAtPersian, src => src.CreatedAtPersian);
|
||||
|
||||
config.NewConfig<PlaceDiscountOrderResponseDto, ProtoDto.PlaceDiscountOrderResponse>()
|
||||
.Map(dest => dest.Success, src => src.Success)
|
||||
.Map(dest => dest.Message, src => src.Message)
|
||||
.Map(dest => dest.OrderId, src => src.OrderId)
|
||||
.Map(dest => dest.OrderNumber, src => src.OrderId.ToString())
|
||||
.Map(dest => dest.PaymentUrl, src => src.PaymentUrl);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkTree;
|
||||
using FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkStatistics;
|
||||
using FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkPosition;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using ProtoDto = FrontOffice.BFF.NetworkMembership.Protobuf.Protos.NetworkMembership;
|
||||
|
||||
namespace FrontOffice.BFF.WebApi.Common.Mappings;
|
||||
|
||||
public class NetworkMembershipProfile : IRegister
|
||||
{
|
||||
void IRegister.Register(TypeAdapterConfig config)
|
||||
{
|
||||
// Request -> Query mappings
|
||||
config.NewConfig<ProtoDto.GetMyNetworkTreeRequest, GetMyNetworkTreeQuery>()
|
||||
.Map(dest => dest.MaxDepth, src => src.MaxDepth > 0 ? src.MaxDepth : 3);
|
||||
|
||||
// Response mappings - Tree
|
||||
config.NewConfig<GetMyNetworkTreeResponseDto, ProtoDto.GetMyNetworkTreeResponse>()
|
||||
.Map(dest => dest.RootNode, src => src.RootNode)
|
||||
.Map(dest => dest.TotalMembers, src => src.TotalMembers)
|
||||
.Map(dest => dest.CurrentDepth, src => src.CurrentDepth);
|
||||
|
||||
config.NewConfig<NetworkNodeDto, ProtoDto.NetworkNodeModel>()
|
||||
.Map(dest => dest.UserId, src => src.UserId)
|
||||
.Map(dest => dest.FullName, src => src.FullName)
|
||||
.Map(dest => dest.Mobile, src => src.Mobile)
|
||||
.Map(dest => dest.Avatar, src => src.Avatar)
|
||||
.Map(dest => dest.Position, src => src.Position)
|
||||
.Map(dest => dest.LeftChild, src => src.LeftChild)
|
||||
.Map(dest => dest.RightChild, src => src.RightChild)
|
||||
.Map(dest => dest.Level, src => src.Level)
|
||||
.Map(dest => dest.HasChildren, src => src.HasChildren);
|
||||
|
||||
// Response mappings - Statistics
|
||||
config.NewConfig<GetMyNetworkStatisticsResponseDto, ProtoDto.GetMyNetworkStatisticsResponse>()
|
||||
.Map(dest => dest.TotalMembers, src => src.TotalMembers)
|
||||
.Map(dest => dest.ActiveMembers, src => src.ActiveMembers)
|
||||
.Map(dest => dest.LeftLegCount, src => src.LeftLegCount)
|
||||
.Map(dest => dest.RightLegCount, src => src.RightLegCount)
|
||||
.Map(dest => dest.LeftPercentage, src => src.LeftPercentage)
|
||||
.Map(dest => dest.RightPercentage, src => src.RightPercentage)
|
||||
.Map(dest => dest.AverageDepth, src => src.AverageDepth)
|
||||
.Map(dest => dest.MaxDepth, src => src.MaxDepth)
|
||||
.Map(dest => dest.WeakerLeg, src => src.WeakerLeg)
|
||||
.Map(dest => dest.MyNetworkLevel, src => src.MyNetworkLevel)
|
||||
.Map(dest => dest.MyNetworkLeg, src => src.MyNetworkLeg)
|
||||
.Map(dest => dest.MyReferralCode, src => src.MyReferralCode)
|
||||
.Map(dest => dest.LastMember, src => src.LastMember);
|
||||
|
||||
config.NewConfig<LastMemberDto, ProtoDto.LastMemberModel>()
|
||||
.Map(dest => dest.UserId, src => src.UserId)
|
||||
.Map(dest => dest.FullName, src => src.FullName)
|
||||
.Map(dest => dest.Position, src => src.Position)
|
||||
.Map(dest => dest.TotalChildren, src => src.TotalChildren);
|
||||
|
||||
// Response mappings - Position
|
||||
config.NewConfig<GetMyNetworkPositionResponseDto, ProtoDto.GetMyNetworkPositionResponse>()
|
||||
.Map(dest => dest.UserId, src => src.UserId)
|
||||
.Map(dest => dest.ParentId, src => src.ParentId)
|
||||
.Map(dest => dest.ParentName, src => src.ParentName)
|
||||
.Map(dest => dest.Position, src => src.Position)
|
||||
.Map(dest => dest.Level, src => src.Level)
|
||||
.Map(dest => dest.ReferralCode, src => src.ReferralCode)
|
||||
.Map(dest => dest.JoinedAt, src => Timestamp.FromDateTime(DateTime.SpecifyKind(src.JoinedAt, DateTimeKind.Utc)))
|
||||
.Map(dest => dest.HasLeftChild, src => src.HasLeftChild)
|
||||
.Map(dest => dest.HasRightChild, src => src.HasRightChild);
|
||||
}
|
||||
}
|
||||
@@ -31,5 +31,9 @@
|
||||
<ProjectReference Include="..\Protobufs\FrontOffice.BFF.UserAddress.Protobuf\FrontOffice.BFF.UserAddress.Protobuf.csproj" />
|
||||
<ProjectReference Include="..\Protobufs\FrontOffice.BFF.Package.Protobuf\FrontOffice.BFF.Package.Protobuf.csproj" />
|
||||
<ProjectReference Include="..\Protobufs\FrontOffice.BFF.UserOrder.Protobuf\FrontOffice.BFF.UserOrder.Protobuf.csproj" />
|
||||
<ProjectReference Include="..\Protobufs\FrontOffice.BFF.DiscountShop.Protobuf\FrontOffice.BFF.DiscountShop.Protobuf.csproj" />
|
||||
<ProjectReference Include="..\Protobufs\FrontOffice.BFF.Commission.Protobuf\FrontOffice.BFF.Commission.Protobuf.csproj" />
|
||||
<ProjectReference Include="..\Protobufs\FrontOffice.BFF.ClubMembership.Protobuf\FrontOffice.BFF.ClubMembership.Protobuf.csproj" />
|
||||
<ProjectReference Include="..\Protobufs\FrontOffice.BFF.NetworkMembership.Protobuf\FrontOffice.BFF.NetworkMembership.Protobuf.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using FrontOffice.BFF.WebApi.Common.Services;
|
||||
using FrontOffice.BFF.Application.ClubMembershipCQ.Queries.GetMyClubMembership;
|
||||
using FrontOffice.BFF.Application.ClubMembershipCQ.Commands.ActivateMyClubMembership;
|
||||
using FrontOffice.BFF.ClubMembership.Protobuf.Protos.ClubMembership;
|
||||
|
||||
namespace FrontOffice.BFF.WebApi.Services;
|
||||
|
||||
/// <summary>
|
||||
/// سرویس عضویت باشگاه - برای کاربران FrontOffice
|
||||
/// </summary>
|
||||
public class ClubMembershipGrpcService : ClubMembershipContract.ClubMembershipContractBase
|
||||
{
|
||||
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
||||
|
||||
public ClubMembershipGrpcService(IDispatchRequestToCQRS dispatchRequestToCQRS)
|
||||
{
|
||||
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت وضعیت عضویت باشگاه کاربر جاری
|
||||
/// </summary>
|
||||
public override async Task<GetMyClubMembershipResponse> GetMyClubMembership(Empty request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetMyClubMembershipQuery, GetMyClubMembershipResponse>(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// فعالسازی عضویت باشگاه (پرداخت 56M)
|
||||
/// </summary>
|
||||
public override async Task<ActivateMyClubMembershipResponse> ActivateMyClubMembership(ActivateMyClubMembershipRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<ActivateMyClubMembershipRequest, ActivateMyClubMembershipCommand, ActivateMyClubMembershipResponse>(request, context);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using FrontOffice.BFF.WebApi.Common.Services;
|
||||
using FrontOffice.BFF.Application.ClubMembershipCQ.Queries.GetMyClubMembership;
|
||||
using FrontOffice.BFF.Application.ClubMembershipCQ.Commands.ActivateMyClubMembership;
|
||||
using MediatR;
|
||||
using System.Threading;
|
||||
|
||||
namespace FrontOffice.BFF.WebApi.Services;
|
||||
|
||||
@@ -11,19 +13,19 @@ namespace FrontOffice.BFF.WebApi.Services;
|
||||
/// </summary>
|
||||
public class ClubMembershipService
|
||||
{
|
||||
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
||||
private readonly ISender _sender;
|
||||
|
||||
public ClubMembershipService(IDispatchRequestToCQRS dispatchRequestToCQRS)
|
||||
public ClubMembershipService(ISender sender)
|
||||
{
|
||||
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||
_sender = sender;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت وضعیت عضویت باشگاه کاربر جاری
|
||||
/// </summary>
|
||||
public async Task<GetMyClubMembershipResponseDto> GetMyClubMembership(Empty request, ServerCallContext context)
|
||||
public async Task<GetMyClubMembershipResponseDto> GetMyClubMembership(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetMyClubMembershipQuery, GetMyClubMembershipResponseDto>(context);
|
||||
return await _sender.Send(new GetMyClubMembershipQuery(), cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -31,8 +33,8 @@ public class ClubMembershipService
|
||||
/// </summary>
|
||||
public async Task<ActivateMyClubMembershipResponseDto> ActivateMyClubMembership(
|
||||
ActivateMyClubMembershipCommand request,
|
||||
ServerCallContext context)
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<ActivateMyClubMembershipCommand, ActivateMyClubMembershipResponseDto>(request, context);
|
||||
return await _sender.Send(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
35
src/FrontOffice.BFF.WebApi/Services/CommissionService.cs
Normal file
35
src/FrontOffice.BFF.WebApi/Services/CommissionService.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using FrontOffice.BFF.WebApi.Common.Services;
|
||||
using FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
|
||||
using FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyWeeklyBalances;
|
||||
using FrontOffice.BFF.Commission.Protobuf.Protos.Commission;
|
||||
|
||||
namespace FrontOffice.BFF.WebApi.Services;
|
||||
|
||||
/// <summary>
|
||||
/// سرویس کمیسیون - برای کاربران FrontOffice
|
||||
/// </summary>
|
||||
public class CommissionService : CommissionContract.CommissionContractBase
|
||||
{
|
||||
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
||||
|
||||
public CommissionService(IDispatchRequestToCQRS dispatchRequestToCQRS)
|
||||
{
|
||||
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت لیست پرداختهای کمیسیون کاربر
|
||||
/// </summary>
|
||||
public override async Task<GetMyCommissionPayoutsResponse> GetMyCommissionPayouts(GetMyCommissionPayoutsRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetMyCommissionPayoutsRequest, GetMyCommissionPayoutsQuery, GetMyCommissionPayoutsResponse>(request, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت لیست بالانسهای هفتگی کاربر
|
||||
/// </summary>
|
||||
public override async Task<GetMyWeeklyBalancesResponse> GetMyWeeklyBalances(GetMyWeeklyBalancesRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetMyWeeklyBalancesRequest, GetMyWeeklyBalancesQuery, GetMyWeeklyBalancesResponse>(request, context);
|
||||
}
|
||||
}
|
||||
80
src/FrontOffice.BFF.WebApi/Services/DiscountShopService.cs
Normal file
80
src/FrontOffice.BFF.WebApi/Services/DiscountShopService.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using FrontOffice.BFF.WebApi.Common.Services;
|
||||
using FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetDiscountProducts;
|
||||
using FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetDiscountCategories;
|
||||
using FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetMyDiscountCart;
|
||||
using FrontOffice.BFF.Application.DiscountShopCQ.Queries.GetMyDiscountOrders;
|
||||
using FrontOffice.BFF.Application.DiscountShopCQ.Commands.AddToDiscountCart;
|
||||
using FrontOffice.BFF.Application.DiscountShopCQ.Commands.RemoveFromDiscountCart;
|
||||
using FrontOffice.BFF.Application.DiscountShopCQ.Commands.PlaceDiscountOrder;
|
||||
using FrontOffice.BFF.DiscountShop.Protobuf.Protos.DiscountShop;
|
||||
|
||||
namespace FrontOffice.BFF.WebApi.Services;
|
||||
|
||||
/// <summary>
|
||||
/// سرویس فروشگاه تخفیفی - برای کاربران عضو باشگاه
|
||||
/// </summary>
|
||||
public class DiscountShopService : DiscountShopContract.DiscountShopContractBase
|
||||
{
|
||||
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
||||
|
||||
public DiscountShopService(IDispatchRequestToCQRS dispatchRequestToCQRS)
|
||||
{
|
||||
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت لیست محصولات تخفیفی
|
||||
/// </summary>
|
||||
public override async Task<GetDiscountProductsResponse> GetDiscountProducts(GetDiscountProductsRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetDiscountProductsRequest, GetDiscountProductsQuery, GetDiscountProductsResponse>(request, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت دستهبندیهای فروشگاه تخفیفی
|
||||
/// </summary>
|
||||
public override async Task<GetDiscountCategoriesResponse> GetDiscountCategories(GetDiscountCategoriesRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetDiscountCategoriesRequest, GetDiscountCategoriesQuery, GetDiscountCategoriesResponse>(request, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت سبد خرید تخفیفی کاربر جاری
|
||||
/// </summary>
|
||||
public override async Task<GetMyDiscountCartResponse> GetMyDiscountCart(Empty request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetMyDiscountCartQuery, GetMyDiscountCartResponse>(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// افزودن محصول به سبد خرید تخفیفی
|
||||
/// </summary>
|
||||
public override async Task<Empty> AddToDiscountCart(AddToDiscountCartRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<AddToDiscountCartRequest, AddToDiscountCartCommand>(request, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// حذف محصول از سبد خرید تخفیفی
|
||||
/// </summary>
|
||||
public override async Task<Empty> RemoveFromDiscountCart(RemoveFromDiscountCartRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<RemoveFromDiscountCartRequest, RemoveFromDiscountCartCommand>(request, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت لیست سفارشات تخفیفی کاربر جاری
|
||||
/// </summary>
|
||||
public override async Task<GetMyDiscountOrdersResponse> GetMyDiscountOrders(GetMyDiscountOrdersRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetMyDiscountOrdersRequest, GetMyDiscountOrdersQuery, GetMyDiscountOrdersResponse>(request, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ثبت سفارش تخفیفی
|
||||
/// </summary>
|
||||
public override async Task<PlaceDiscountOrderResponse> PlaceDiscountOrder(PlaceDiscountOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<PlaceDiscountOrderRequest, PlaceDiscountOrderCommand, PlaceDiscountOrderResponse>(request, context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using FrontOffice.BFF.WebApi.Common.Services;
|
||||
using FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkTree;
|
||||
using FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkStatistics;
|
||||
using FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkPosition;
|
||||
using FrontOffice.BFF.NetworkMembership.Protobuf.Protos.NetworkMembership;
|
||||
|
||||
namespace FrontOffice.BFF.WebApi.Services;
|
||||
|
||||
/// <summary>
|
||||
/// سرویس عضویت شبکهای - برای کاربران FrontOffice
|
||||
/// </summary>
|
||||
public class NetworkMembershipService : NetworkMembershipContract.NetworkMembershipContractBase
|
||||
{
|
||||
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
||||
|
||||
public NetworkMembershipService(IDispatchRequestToCQRS dispatchRequestToCQRS)
|
||||
{
|
||||
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت درخت شبکه کاربر جاری
|
||||
/// </summary>
|
||||
public override async Task<GetMyNetworkTreeResponse> GetMyNetworkTree(GetMyNetworkTreeRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetMyNetworkTreeRequest, GetMyNetworkTreeQuery, GetMyNetworkTreeResponse>(request, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت آمار شبکه کاربر جاری
|
||||
/// </summary>
|
||||
public override async Task<GetMyNetworkStatisticsResponse> GetMyNetworkStatistics(Empty request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetMyNetworkStatisticsQuery, GetMyNetworkStatisticsResponse>(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت موقعیت کاربر در شبکه
|
||||
/// </summary>
|
||||
public override async Task<GetMyNetworkPositionResponse> GetMyNetworkPosition(Empty request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetMyNetworkPositionQuery, GetMyNetworkPositionResponse>(context);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
@@ -30,64 +31,228 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrontOffice.BFF.ShopingCart
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrontOffice.BFF.UserWallet.Protobuf", "Protobufs\FrontOffice.BFF.UserWallet.Protobuf\FrontOffice.BFF.UserWallet.Protobuf.csproj", "{03F99CE9-F952-47B0-B71A-1F4865E52443}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrontOffice.BFF.DiscountShop.Protobuf", "Protobufs\FrontOffice.BFF.DiscountShop.Protobuf\FrontOffice.BFF.DiscountShop.Protobuf.csproj", "{5547FB9B-7AEF-49C7-AA11-119D37DD9528}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrontOffice.BFF.Commission.Protobuf", "Protobufs\FrontOffice.BFF.Commission.Protobuf\FrontOffice.BFF.Commission.Protobuf.csproj", "{B1380466-18E7-4CAD-88F8-E1419D2B6300}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrontOffice.BFF.ClubMembership.Protobuf", "Protobufs\FrontOffice.BFF.ClubMembership.Protobuf\FrontOffice.BFF.ClubMembership.Protobuf.csproj", "{B6EAE0A3-3427-4D86-B2BA-B185F476B74F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrontOffice.BFF.NetworkMembership.Protobuf", "Protobufs\FrontOffice.BFF.NetworkMembership.Protobuf\FrontOffice.BFF.NetworkMembership.Protobuf.csproj", "{CCA23A57-4BC4-4C53-9A96-41FCFF5407F5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{7E733B83-275C-4639-AA10-4A59B681B904}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7E733B83-275C-4639-AA10-4A59B681B904}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7E733B83-275C-4639-AA10-4A59B681B904}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{7E733B83-275C-4639-AA10-4A59B681B904}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{7E733B83-275C-4639-AA10-4A59B681B904}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{7E733B83-275C-4639-AA10-4A59B681B904}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{7E733B83-275C-4639-AA10-4A59B681B904}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7E733B83-275C-4639-AA10-4A59B681B904}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7E733B83-275C-4639-AA10-4A59B681B904}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{7E733B83-275C-4639-AA10-4A59B681B904}.Release|x64.Build.0 = Release|Any CPU
|
||||
{7E733B83-275C-4639-AA10-4A59B681B904}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{7E733B83-275C-4639-AA10-4A59B681B904}.Release|x86.Build.0 = Release|Any CPU
|
||||
{56107B61-262D-413A-A9B6-4F3730220415}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{56107B61-262D-413A-A9B6-4F3730220415}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{56107B61-262D-413A-A9B6-4F3730220415}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{56107B61-262D-413A-A9B6-4F3730220415}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{56107B61-262D-413A-A9B6-4F3730220415}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{56107B61-262D-413A-A9B6-4F3730220415}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{56107B61-262D-413A-A9B6-4F3730220415}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{56107B61-262D-413A-A9B6-4F3730220415}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{56107B61-262D-413A-A9B6-4F3730220415}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{56107B61-262D-413A-A9B6-4F3730220415}.Release|x64.Build.0 = Release|Any CPU
|
||||
{56107B61-262D-413A-A9B6-4F3730220415}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{56107B61-262D-413A-A9B6-4F3730220415}.Release|x86.Build.0 = Release|Any CPU
|
||||
{41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Release|x64.Build.0 = Release|Any CPU
|
||||
{41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Release|x86.Build.0 = Release|Any CPU
|
||||
{1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Release|x64.Build.0 = Release|Any CPU
|
||||
{1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F4E98BE4-6F95-4B4E-924D-CBAD02AF24F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F4E98BE4-6F95-4B4E-924D-CBAD02AF24F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F4E98BE4-6F95-4B4E-924D-CBAD02AF24F1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F4E98BE4-6F95-4B4E-924D-CBAD02AF24F1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F4E98BE4-6F95-4B4E-924D-CBAD02AF24F1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F4E98BE4-6F95-4B4E-924D-CBAD02AF24F1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F4E98BE4-6F95-4B4E-924D-CBAD02AF24F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F4E98BE4-6F95-4B4E-924D-CBAD02AF24F1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F4E98BE4-6F95-4B4E-924D-CBAD02AF24F1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F4E98BE4-6F95-4B4E-924D-CBAD02AF24F1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F4E98BE4-6F95-4B4E-924D-CBAD02AF24F1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F4E98BE4-6F95-4B4E-924D-CBAD02AF24F1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C8A16685-0A51-4D1A-B399-FB94C90D9BDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C8A16685-0A51-4D1A-B399-FB94C90D9BDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C8A16685-0A51-4D1A-B399-FB94C90D9BDC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C8A16685-0A51-4D1A-B399-FB94C90D9BDC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C8A16685-0A51-4D1A-B399-FB94C90D9BDC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C8A16685-0A51-4D1A-B399-FB94C90D9BDC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C8A16685-0A51-4D1A-B399-FB94C90D9BDC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C8A16685-0A51-4D1A-B399-FB94C90D9BDC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C8A16685-0A51-4D1A-B399-FB94C90D9BDC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C8A16685-0A51-4D1A-B399-FB94C90D9BDC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C8A16685-0A51-4D1A-B399-FB94C90D9BDC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C8A16685-0A51-4D1A-B399-FB94C90D9BDC}.Release|x86.Build.0 = Release|Any CPU
|
||||
{D70F0C9A-E954-4A67-B23D-9BE22721BD5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D70F0C9A-E954-4A67-B23D-9BE22721BD5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D70F0C9A-E954-4A67-B23D-9BE22721BD5D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{D70F0C9A-E954-4A67-B23D-9BE22721BD5D}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{D70F0C9A-E954-4A67-B23D-9BE22721BD5D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{D70F0C9A-E954-4A67-B23D-9BE22721BD5D}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{D70F0C9A-E954-4A67-B23D-9BE22721BD5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D70F0C9A-E954-4A67-B23D-9BE22721BD5D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D70F0C9A-E954-4A67-B23D-9BE22721BD5D}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{D70F0C9A-E954-4A67-B23D-9BE22721BD5D}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D70F0C9A-E954-4A67-B23D-9BE22721BD5D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D70F0C9A-E954-4A67-B23D-9BE22721BD5D}.Release|x86.Build.0 = Release|Any CPU
|
||||
{663CDDFA-E15F-4356-AE01-2311C9B83D52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{663CDDFA-E15F-4356-AE01-2311C9B83D52}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{663CDDFA-E15F-4356-AE01-2311C9B83D52}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{663CDDFA-E15F-4356-AE01-2311C9B83D52}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{663CDDFA-E15F-4356-AE01-2311C9B83D52}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{663CDDFA-E15F-4356-AE01-2311C9B83D52}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{663CDDFA-E15F-4356-AE01-2311C9B83D52}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{663CDDFA-E15F-4356-AE01-2311C9B83D52}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{663CDDFA-E15F-4356-AE01-2311C9B83D52}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{663CDDFA-E15F-4356-AE01-2311C9B83D52}.Release|x64.Build.0 = Release|Any CPU
|
||||
{663CDDFA-E15F-4356-AE01-2311C9B83D52}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{663CDDFA-E15F-4356-AE01-2311C9B83D52}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F59861D9-01D6-44C9-85A9-E6050D55D290}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F59861D9-01D6-44C9-85A9-E6050D55D290}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F59861D9-01D6-44C9-85A9-E6050D55D290}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F59861D9-01D6-44C9-85A9-E6050D55D290}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F59861D9-01D6-44C9-85A9-E6050D55D290}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F59861D9-01D6-44C9-85A9-E6050D55D290}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F59861D9-01D6-44C9-85A9-E6050D55D290}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F59861D9-01D6-44C9-85A9-E6050D55D290}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F59861D9-01D6-44C9-85A9-E6050D55D290}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F59861D9-01D6-44C9-85A9-E6050D55D290}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F59861D9-01D6-44C9-85A9-E6050D55D290}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F59861D9-01D6-44C9-85A9-E6050D55D290}.Release|x86.Build.0 = Release|Any CPU
|
||||
{CB77669F-5B48-4AC6-B20E-A928660E93F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CB77669F-5B48-4AC6-B20E-A928660E93F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CB77669F-5B48-4AC6-B20E-A928660E93F8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{CB77669F-5B48-4AC6-B20E-A928660E93F8}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{CB77669F-5B48-4AC6-B20E-A928660E93F8}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{CB77669F-5B48-4AC6-B20E-A928660E93F8}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{CB77669F-5B48-4AC6-B20E-A928660E93F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CB77669F-5B48-4AC6-B20E-A928660E93F8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CB77669F-5B48-4AC6-B20E-A928660E93F8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{CB77669F-5B48-4AC6-B20E-A928660E93F8}.Release|x64.Build.0 = Release|Any CPU
|
||||
{CB77669F-5B48-4AC6-B20E-A928660E93F8}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{CB77669F-5B48-4AC6-B20E-A928660E93F8}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E3F6D1B7-DB78-4F36-BE77-2F9D2D7B5B7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E3F6D1B7-DB78-4F36-BE77-2F9D2D7B5B7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E3F6D1B7-DB78-4F36-BE77-2F9D2D7B5B7C}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E3F6D1B7-DB78-4F36-BE77-2F9D2D7B5B7C}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E3F6D1B7-DB78-4F36-BE77-2F9D2D7B5B7C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E3F6D1B7-DB78-4F36-BE77-2F9D2D7B5B7C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E3F6D1B7-DB78-4F36-BE77-2F9D2D7B5B7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E3F6D1B7-DB78-4F36-BE77-2F9D2D7B5B7C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E3F6D1B7-DB78-4F36-BE77-2F9D2D7B5B7C}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E3F6D1B7-DB78-4F36-BE77-2F9D2D7B5B7C}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E3F6D1B7-DB78-4F36-BE77-2F9D2D7B5B7C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E3F6D1B7-DB78-4F36-BE77-2F9D2D7B5B7C}.Release|x86.Build.0 = Release|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Release|x64.Build.0 = Release|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7}.Release|x86.Build.0 = Release|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Release|x64.Build.0 = Release|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443}.Release|x86.Build.0 = Release|Any CPU
|
||||
{5547FB9B-7AEF-49C7-AA11-119D37DD9528}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5547FB9B-7AEF-49C7-AA11-119D37DD9528}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5547FB9B-7AEF-49C7-AA11-119D37DD9528}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{5547FB9B-7AEF-49C7-AA11-119D37DD9528}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{5547FB9B-7AEF-49C7-AA11-119D37DD9528}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5547FB9B-7AEF-49C7-AA11-119D37DD9528}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5547FB9B-7AEF-49C7-AA11-119D37DD9528}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5547FB9B-7AEF-49C7-AA11-119D37DD9528}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5547FB9B-7AEF-49C7-AA11-119D37DD9528}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{5547FB9B-7AEF-49C7-AA11-119D37DD9528}.Release|x64.Build.0 = Release|Any CPU
|
||||
{5547FB9B-7AEF-49C7-AA11-119D37DD9528}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5547FB9B-7AEF-49C7-AA11-119D37DD9528}.Release|x86.Build.0 = Release|Any CPU
|
||||
{B1380466-18E7-4CAD-88F8-E1419D2B6300}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B1380466-18E7-4CAD-88F8-E1419D2B6300}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B1380466-18E7-4CAD-88F8-E1419D2B6300}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{B1380466-18E7-4CAD-88F8-E1419D2B6300}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{B1380466-18E7-4CAD-88F8-E1419D2B6300}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{B1380466-18E7-4CAD-88F8-E1419D2B6300}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{B1380466-18E7-4CAD-88F8-E1419D2B6300}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B1380466-18E7-4CAD-88F8-E1419D2B6300}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B1380466-18E7-4CAD-88F8-E1419D2B6300}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{B1380466-18E7-4CAD-88F8-E1419D2B6300}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B1380466-18E7-4CAD-88F8-E1419D2B6300}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B1380466-18E7-4CAD-88F8-E1419D2B6300}.Release|x86.Build.0 = Release|Any CPU
|
||||
{B6EAE0A3-3427-4D86-B2BA-B185F476B74F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B6EAE0A3-3427-4D86-B2BA-B185F476B74F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B6EAE0A3-3427-4D86-B2BA-B185F476B74F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{B6EAE0A3-3427-4D86-B2BA-B185F476B74F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{B6EAE0A3-3427-4D86-B2BA-B185F476B74F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{B6EAE0A3-3427-4D86-B2BA-B185F476B74F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{B6EAE0A3-3427-4D86-B2BA-B185F476B74F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B6EAE0A3-3427-4D86-B2BA-B185F476B74F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B6EAE0A3-3427-4D86-B2BA-B185F476B74F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{B6EAE0A3-3427-4D86-B2BA-B185F476B74F}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B6EAE0A3-3427-4D86-B2BA-B185F476B74F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B6EAE0A3-3427-4D86-B2BA-B185F476B74F}.Release|x86.Build.0 = Release|Any CPU
|
||||
{CCA23A57-4BC4-4C53-9A96-41FCFF5407F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CCA23A57-4BC4-4C53-9A96-41FCFF5407F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CCA23A57-4BC4-4C53-9A96-41FCFF5407F5}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{CCA23A57-4BC4-4C53-9A96-41FCFF5407F5}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{CCA23A57-4BC4-4C53-9A96-41FCFF5407F5}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{CCA23A57-4BC4-4C53-9A96-41FCFF5407F5}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{CCA23A57-4BC4-4C53-9A96-41FCFF5407F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CCA23A57-4BC4-4C53-9A96-41FCFF5407F5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CCA23A57-4BC4-4C53-9A96-41FCFF5407F5}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{CCA23A57-4BC4-4C53-9A96-41FCFF5407F5}.Release|x64.Build.0 = Release|Any CPU
|
||||
{CCA23A57-4BC4-4C53-9A96-41FCFF5407F5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{CCA23A57-4BC4-4C53-9A96-41FCFF5407F5}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -99,8 +264,12 @@ Global
|
||||
{663CDDFA-E15F-4356-AE01-2311C9B83D52} = {CA9BF4D6-6729-4011-888E-48F5F739B469}
|
||||
{F59861D9-01D6-44C9-85A9-E6050D55D290} = {CA9BF4D6-6729-4011-888E-48F5F739B469}
|
||||
{CB77669F-5B48-4AC6-B20E-A928660E93F8} = {CA9BF4D6-6729-4011-888E-48F5F739B469}
|
||||
{E3F6D1B7-DB78-4F36-BE77-2F9D2D7B5B7C} = {CA9BF4D6-6729-4011-888E-48F5F739B469}
|
||||
{DC61324B-D389-4A1D-B048-D0AA43A6BBE7} = {CA9BF4D6-6729-4011-888E-48F5F739B469}
|
||||
{03F99CE9-F952-47B0-B71A-1F4865E52443} = {CA9BF4D6-6729-4011-888E-48F5F739B469}
|
||||
{E3F6D1B7-DB78-4F36-BE77-2F9D2D7B5B7C} = {CA9BF4D6-6729-4011-888E-48F5F739B469}
|
||||
{5547FB9B-7AEF-49C7-AA11-119D37DD9528} = {CA9BF4D6-6729-4011-888E-48F5F739B469}
|
||||
{B1380466-18E7-4CAD-88F8-E1419D2B6300} = {CA9BF4D6-6729-4011-888E-48F5F739B469}
|
||||
{B6EAE0A3-3427-4D86-B2BA-B185F476B74F} = {CA9BF4D6-6729-4011-888E-48F5F739B469}
|
||||
{CCA23A57-4BC4-4C53-9A96-41FCFF5407F5} = {CA9BF4D6-6729-4011-888E-48F5F739B469}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using FluentValidation;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
public static class ConfigureServices
|
||||
{
|
||||
public static IServiceCollection AddClubMembershipProtobufServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>0.0.1</Version>
|
||||
<PackageId>Foursat.FrontOffice.BFF.ClubMembership.Protobuf</PackageId>
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<DebugSymbols>False</DebugSymbols>
|
||||
<DebugType>None</DebugType>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.23.3" />
|
||||
<PackageReference Include="Grpc.Core.Api" Version="2.54.0" />
|
||||
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.2.2" />
|
||||
<PackageReference Include="Google.Api.CommonProtos" Version="2.10.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.55.1" >
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Protobuf Include="Protos\clubmembership.proto" ProtoRoot="Protos\" GrpcServices="Both" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,61 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package clubmembership;
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
import "google/protobuf/wrappers.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "google/api/annotations.proto";
|
||||
|
||||
option csharp_namespace = "FrontOffice.BFF.ClubMembership.Protobuf.Protos.ClubMembership";
|
||||
|
||||
// سرویس عضویت باشگاه - برای کاربران FrontOffice
|
||||
service ClubMembershipContract
|
||||
{
|
||||
// دریافت وضعیت عضویت باشگاه کاربر جاری
|
||||
rpc GetMyClubMembership(google.protobuf.Empty) returns (GetMyClubMembershipResponse){
|
||||
option (google.api.http) = {
|
||||
get: "/ClubMembership/MyStatus"
|
||||
};
|
||||
};
|
||||
|
||||
// فعالسازی عضویت باشگاه (پرداخت 56M)
|
||||
rpc ActivateMyClubMembership(ActivateMyClubMembershipRequest) returns (ActivateMyClubMembershipResponse){
|
||||
option (google.api.http) = {
|
||||
post: "/ClubMembership/Activate"
|
||||
body: "*"
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// ============ GetMyClubMembership ============
|
||||
message GetMyClubMembershipResponse
|
||||
{
|
||||
int64 user_id = 1;
|
||||
int64 package_id = 2;
|
||||
string package_name = 3;
|
||||
string activation_code = 4;
|
||||
bool is_active = 5;
|
||||
google.protobuf.Timestamp activation_date = 6;
|
||||
google.protobuf.Timestamp expiration_date = 7;
|
||||
string status = 8; // Trial/Active/Expired/Inactive
|
||||
int32 days_remaining = 9;
|
||||
bool is_trial_period = 10;
|
||||
}
|
||||
|
||||
// ============ ActivateMyClubMembership ============
|
||||
message ActivateMyClubMembershipRequest
|
||||
{
|
||||
int64 package_id = 1;
|
||||
google.protobuf.StringValue activation_code = 2;
|
||||
int32 duration_months = 3; // پیشفرض: 12
|
||||
}
|
||||
|
||||
message ActivateMyClubMembershipResponse
|
||||
{
|
||||
bool success = 1;
|
||||
string message = 2;
|
||||
google.protobuf.Timestamp activation_date = 3;
|
||||
google.protobuf.Timestamp expiration_date = 4;
|
||||
int64 amount_paid = 5;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2015, Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
import "google/api/http.proto";
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "AnnotationsProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
extend google.protobuf.MethodOptions {
|
||||
// See `HttpRule`.
|
||||
HttpRule http = 72295728;
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
// Copyright 2019 Google LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
option cc_enable_arenas = true;
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "HttpProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// Defines the HTTP configuration for an API service. It contains a list of
|
||||
// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method
|
||||
// to one or more HTTP REST API methods.
|
||||
message Http {
|
||||
// A list of HTTP configuration rules that apply to individual API methods.
|
||||
//
|
||||
// **NOTE:** All service configuration rules follow "last one wins" order.
|
||||
repeated HttpRule rules = 1;
|
||||
|
||||
// When set to true, URL path parameters will be fully URI-decoded except in
|
||||
// cases of single segment matches in reserved expansion, where "%2F" will be
|
||||
// left encoded.
|
||||
//
|
||||
// The default behavior is to not decode RFC 6570 reserved characters in multi
|
||||
// segment matches.
|
||||
bool fully_decode_reserved_expansion = 2;
|
||||
}
|
||||
|
||||
// # gRPC Transcoding
|
||||
//
|
||||
// gRPC Transcoding is a feature for mapping between a gRPC method and one or
|
||||
// more HTTP REST endpoints. It allows developers to build a single API service
|
||||
// that supports both gRPC APIs and REST APIs. Many systems, including [Google
|
||||
// APIs](https://github.com/googleapis/googleapis),
|
||||
// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC
|
||||
// Gateway](https://github.com/grpc-ecosystem/grpc-gateway),
|
||||
// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature
|
||||
// and use it for large scale production services.
|
||||
//
|
||||
// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies
|
||||
// how different portions of the gRPC request message are mapped to the URL
|
||||
// path, URL query parameters, and HTTP request body. It also controls how the
|
||||
// gRPC response message is mapped to the HTTP response body. `HttpRule` is
|
||||
// typically specified as an `google.api.http` annotation on the gRPC method.
|
||||
//
|
||||
// Each mapping specifies a URL path template and an HTTP method. The path
|
||||
// template may refer to one or more fields in the gRPC request message, as long
|
||||
// as each field is a non-repeated field with a primitive (non-message) type.
|
||||
// The path template controls how fields of the request message are mapped to
|
||||
// the URL path.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get: "/v1/{name=messages/*}"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// string name = 1; // Mapped to URL path.
|
||||
// }
|
||||
// message Message {
|
||||
// string text = 1; // The resource content.
|
||||
// }
|
||||
//
|
||||
// This enables an HTTP REST to gRPC mapping as below:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")`
|
||||
//
|
||||
// Any fields in the request message which are not bound by the path template
|
||||
// automatically become HTTP query parameters if there is no HTTP request body.
|
||||
// For example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get:"/v1/messages/{message_id}"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// message SubMessage {
|
||||
// string subfield = 1;
|
||||
// }
|
||||
// string message_id = 1; // Mapped to URL path.
|
||||
// int64 revision = 2; // Mapped to URL query parameter `revision`.
|
||||
// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`.
|
||||
// }
|
||||
//
|
||||
// This enables a HTTP JSON to RPC mapping as below:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `GET /v1/messages/123456?revision=2&sub.subfield=foo` |
|
||||
// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield:
|
||||
// "foo"))`
|
||||
//
|
||||
// Note that fields which are mapped to URL query parameters must have a
|
||||
// primitive type or a repeated primitive type or a non-repeated message type.
|
||||
// In the case of a repeated type, the parameter can be repeated in the URL
|
||||
// as `...?param=A¶m=B`. In the case of a message type, each field of the
|
||||
// message is mapped to a separate parameter, such as
|
||||
// `...?foo.a=A&foo.b=B&foo.c=C`.
|
||||
//
|
||||
// For HTTP methods that allow a request body, the `body` field
|
||||
// specifies the mapping. Consider a REST update method on the
|
||||
// message resource collection:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// patch: "/v1/messages/{message_id}"
|
||||
// body: "message"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message UpdateMessageRequest {
|
||||
// string message_id = 1; // mapped to the URL
|
||||
// Message message = 2; // mapped to the body
|
||||
// }
|
||||
//
|
||||
// The following HTTP JSON to RPC mapping is enabled, where the
|
||||
// representation of the JSON in the request body is determined by
|
||||
// protos JSON encoding:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id:
|
||||
// "123456" message { text: "Hi!" })`
|
||||
//
|
||||
// The special name `*` can be used in the body mapping to define that
|
||||
// every field not bound by the path template should be mapped to the
|
||||
// request body. This enables the following alternative definition of
|
||||
// the update method:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc UpdateMessage(Message) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// patch: "/v1/messages/{message_id}"
|
||||
// body: "*"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message Message {
|
||||
// string message_id = 1;
|
||||
// string text = 2;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// The following HTTP JSON to RPC mapping is enabled:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id:
|
||||
// "123456" text: "Hi!")`
|
||||
//
|
||||
// Note that when using `*` in the body mapping, it is not possible to
|
||||
// have HTTP parameters, as all fields not bound by the path end in
|
||||
// the body. This makes this option more rarely used in practice when
|
||||
// defining REST APIs. The common usage of `*` is in custom methods
|
||||
// which don't use the URL at all for transferring data.
|
||||
//
|
||||
// It is possible to define multiple HTTP methods for one RPC by using
|
||||
// the `additional_bindings` option. Example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get: "/v1/messages/{message_id}"
|
||||
// additional_bindings {
|
||||
// get: "/v1/users/{user_id}/messages/{message_id}"
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// string message_id = 1;
|
||||
// string user_id = 2;
|
||||
// }
|
||||
//
|
||||
// This enables the following two alternative HTTP JSON to RPC mappings:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")`
|
||||
// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id:
|
||||
// "123456")`
|
||||
//
|
||||
// ## Rules for HTTP mapping
|
||||
//
|
||||
// 1. Leaf request fields (recursive expansion nested messages in the request
|
||||
// message) are classified into three categories:
|
||||
// - Fields referred by the path template. They are passed via the URL path.
|
||||
// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP
|
||||
// request body.
|
||||
// - All other fields are passed via the URL query parameters, and the
|
||||
// parameter name is the field path in the request message. A repeated
|
||||
// field can be represented as multiple query parameters under the same
|
||||
// name.
|
||||
// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields
|
||||
// are passed via URL path and HTTP request body.
|
||||
// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all
|
||||
// fields are passed via URL path and URL query parameters.
|
||||
//
|
||||
// ### Path template syntax
|
||||
//
|
||||
// Template = "/" Segments [ Verb ] ;
|
||||
// Segments = Segment { "/" Segment } ;
|
||||
// Segment = "*" | "**" | LITERAL | Variable ;
|
||||
// Variable = "{" FieldPath [ "=" Segments ] "}" ;
|
||||
// FieldPath = IDENT { "." IDENT } ;
|
||||
// Verb = ":" LITERAL ;
|
||||
//
|
||||
// The syntax `*` matches a single URL path segment. The syntax `**` matches
|
||||
// zero or more URL path segments, which must be the last part of the URL path
|
||||
// except the `Verb`.
|
||||
//
|
||||
// The syntax `Variable` matches part of the URL path as specified by its
|
||||
// template. A variable template must not contain other variables. If a variable
|
||||
// matches a single path segment, its template may be omitted, e.g. `{var}`
|
||||
// is equivalent to `{var=*}`.
|
||||
//
|
||||
// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL`
|
||||
// contains any reserved character, such characters should be percent-encoded
|
||||
// before the matching.
|
||||
//
|
||||
// If a variable contains exactly one path segment, such as `"{var}"` or
|
||||
// `"{var=*}"`, when such a variable is expanded into a URL path on the client
|
||||
// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The
|
||||
// server side does the reverse decoding. Such variables show up in the
|
||||
// [Discovery
|
||||
// Document](https://developers.google.com/discovery/v1/reference/apis) as
|
||||
// `{var}`.
|
||||
//
|
||||
// If a variable contains multiple path segments, such as `"{var=foo/*}"`
|
||||
// or `"{var=**}"`, when such a variable is expanded into a URL path on the
|
||||
// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded.
|
||||
// The server side does the reverse decoding, except "%2F" and "%2f" are left
|
||||
// unchanged. Such variables show up in the
|
||||
// [Discovery
|
||||
// Document](https://developers.google.com/discovery/v1/reference/apis) as
|
||||
// `{+var}`.
|
||||
//
|
||||
// ## Using gRPC API Service Configuration
|
||||
//
|
||||
// gRPC API Service Configuration (service config) is a configuration language
|
||||
// for configuring a gRPC service to become a user-facing product. The
|
||||
// service config is simply the YAML representation of the `google.api.Service`
|
||||
// proto message.
|
||||
//
|
||||
// As an alternative to annotating your proto file, you can configure gRPC
|
||||
// transcoding in your service config YAML files. You do this by specifying a
|
||||
// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same
|
||||
// effect as the proto annotation. This can be particularly useful if you
|
||||
// have a proto that is reused in multiple services. Note that any transcoding
|
||||
// specified in the service config will override any matching transcoding
|
||||
// configuration in the proto.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// http:
|
||||
// rules:
|
||||
// # Selects a gRPC method and applies HttpRule to it.
|
||||
// - selector: example.v1.Messaging.GetMessage
|
||||
// get: /v1/messages/{message_id}/{sub.subfield}
|
||||
//
|
||||
// ## Special notes
|
||||
//
|
||||
// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the
|
||||
// proto to JSON conversion must follow the [proto3
|
||||
// specification](https://developers.google.com/protocol-buffers/docs/proto3#json).
|
||||
//
|
||||
// While the single segment variable follows the semantics of
|
||||
// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String
|
||||
// Expansion, the multi segment variable **does not** follow RFC 6570 Section
|
||||
// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion
|
||||
// does not expand special characters like `?` and `#`, which would lead
|
||||
// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding
|
||||
// for multi segment variables.
|
||||
//
|
||||
// The path variables **must not** refer to any repeated or mapped field,
|
||||
// because client libraries are not capable of handling such variable expansion.
|
||||
//
|
||||
// The path variables **must not** capture the leading "/" character. The reason
|
||||
// is that the most common use case "{var}" does not capture the leading "/"
|
||||
// character. For consistency, all path variables must share the same behavior.
|
||||
//
|
||||
// Repeated message fields must not be mapped to URL query parameters, because
|
||||
// no client library can support such complicated mapping.
|
||||
//
|
||||
// If an API needs to use a JSON array for request or response body, it can map
|
||||
// the request or response body to a repeated field. However, some gRPC
|
||||
// Transcoding implementations may not support this feature.
|
||||
message HttpRule {
|
||||
// Selects a method to which this rule applies.
|
||||
//
|
||||
// Refer to [selector][google.api.DocumentationRule.selector] for syntax details.
|
||||
string selector = 1;
|
||||
|
||||
// Determines the URL pattern is matched by this rules. This pattern can be
|
||||
// used with any of the {get|put|post|delete|patch} methods. A custom method
|
||||
// can be defined using the 'custom' field.
|
||||
oneof pattern {
|
||||
// Maps to HTTP GET. Used for listing and getting information about
|
||||
// resources.
|
||||
string get = 2;
|
||||
|
||||
// Maps to HTTP PUT. Used for replacing a resource.
|
||||
string put = 3;
|
||||
|
||||
// Maps to HTTP POST. Used for creating a resource or performing an action.
|
||||
string post = 4;
|
||||
|
||||
// Maps to HTTP DELETE. Used for deleting a resource.
|
||||
string delete = 5;
|
||||
|
||||
// Maps to HTTP PATCH. Used for updating a resource.
|
||||
string patch = 6;
|
||||
|
||||
// The custom pattern is used for specifying an HTTP method that is not
|
||||
// included in the `pattern` field, such as HEAD, or "*" to leave the
|
||||
// HTTP method unspecified for this rule. The wild-card rule is useful
|
||||
// for services that provide content to Web (HTML) clients.
|
||||
CustomHttpPattern custom = 8;
|
||||
}
|
||||
|
||||
// The name of the request field whose value is mapped to the HTTP request
|
||||
// body, or `*` for mapping all request fields not captured by the path
|
||||
// pattern to the HTTP body, or omitted for not having any HTTP request body.
|
||||
//
|
||||
// NOTE: the referred field must be present at the top-level of the request
|
||||
// message type.
|
||||
string body = 7;
|
||||
|
||||
// Optional. The name of the response field whose value is mapped to the HTTP
|
||||
// response body. When omitted, the entire response message will be used
|
||||
// as the HTTP response body.
|
||||
//
|
||||
// NOTE: The referred field must be present at the top-level of the response
|
||||
// message type.
|
||||
string response_body = 12;
|
||||
|
||||
// Additional HTTP bindings for the selector. Nested bindings must
|
||||
// not contain an `additional_bindings` field themselves (that is,
|
||||
// the nesting may only be one level deep).
|
||||
repeated HttpRule additional_bindings = 11;
|
||||
}
|
||||
|
||||
// A custom pattern is used for defining custom HTTP verb.
|
||||
message CustomHttpPattern {
|
||||
// The name of this custom HTTP verb.
|
||||
string kind = 1;
|
||||
|
||||
// The path matched by this custom verb.
|
||||
string path = 2;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using FluentValidation;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
public static class ConfigureServices
|
||||
{
|
||||
public static IServiceCollection AddCommissionProtobufServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>0.0.1</Version>
|
||||
<PackageId>Foursat.FrontOffice.BFF.Commission.Protobuf</PackageId>
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<DebugSymbols>False</DebugSymbols>
|
||||
<DebugType>None</DebugType>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.23.3" />
|
||||
<PackageReference Include="Grpc.Core.Api" Version="2.54.0" />
|
||||
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.2.2" />
|
||||
<PackageReference Include="Google.Api.CommonProtos" Version="2.10.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.55.1" >
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Protobuf Include="Protos\commission.proto" ProtoRoot="Protos\" GrpcServices="Both" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,94 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package commission;
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
import "google/protobuf/wrappers.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "google/api/annotations.proto";
|
||||
|
||||
option csharp_namespace = "FrontOffice.BFF.Commission.Protobuf.Protos.Commission";
|
||||
|
||||
// سرویس کمیسیون - برای کاربران FrontOffice
|
||||
service CommissionContract
|
||||
{
|
||||
// دریافت لیست پرداختهای کمیسیون کاربر
|
||||
rpc GetMyCommissionPayouts(GetMyCommissionPayoutsRequest) returns (GetMyCommissionPayoutsResponse){
|
||||
option (google.api.http) = {
|
||||
get: "/Commission/MyPayouts"
|
||||
};
|
||||
};
|
||||
|
||||
// دریافت لیست بالانسهای هفتگی کاربر
|
||||
rpc GetMyWeeklyBalances(GetMyWeeklyBalancesRequest) returns (GetMyWeeklyBalancesResponse){
|
||||
option (google.api.http) = {
|
||||
get: "/Commission/MyWeeklyBalances"
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// ============ MetaData ============
|
||||
message MetaData
|
||||
{
|
||||
int64 total_count = 1;
|
||||
}
|
||||
|
||||
// ============ GetMyCommissionPayouts ============
|
||||
message GetMyCommissionPayoutsRequest
|
||||
{
|
||||
int32 page_number = 1;
|
||||
int32 page_size = 2;
|
||||
google.protobuf.StringValue week_number = 3;
|
||||
google.protobuf.Int32Value status = 4; // 0=Pending, 1=Calculated, 2=Paid, 3=Withdrawn
|
||||
}
|
||||
|
||||
message GetMyCommissionPayoutsResponse
|
||||
{
|
||||
MetaData meta_data = 1;
|
||||
repeated CommissionPayoutModel payouts = 2;
|
||||
}
|
||||
|
||||
message CommissionPayoutModel
|
||||
{
|
||||
int64 id = 1;
|
||||
string week_number = 2;
|
||||
string week_label = 3;
|
||||
int32 balances_earned = 4;
|
||||
int64 total_amount = 5;
|
||||
string amount_formatted = 6;
|
||||
string status = 7;
|
||||
string status_badge_color = 8;
|
||||
google.protobuf.Timestamp calculated_date = 9;
|
||||
string date_persian = 10;
|
||||
}
|
||||
|
||||
// ============ GetMyWeeklyBalances ============
|
||||
message GetMyWeeklyBalancesRequest
|
||||
{
|
||||
int32 page_number = 1;
|
||||
int32 page_size = 2;
|
||||
google.protobuf.StringValue week_number = 3;
|
||||
bool only_active = 4;
|
||||
}
|
||||
|
||||
message GetMyWeeklyBalancesResponse
|
||||
{
|
||||
MetaData meta_data = 1;
|
||||
repeated WeeklyBalanceModel balances = 2;
|
||||
int32 total_left_balances = 3;
|
||||
int32 total_right_balances = 4;
|
||||
string weaker_leg = 5;
|
||||
}
|
||||
|
||||
message WeeklyBalanceModel
|
||||
{
|
||||
int64 id = 1;
|
||||
string week_number = 2;
|
||||
int32 left_leg_balances = 3;
|
||||
int32 right_leg_balances = 4;
|
||||
int32 total_balances = 5;
|
||||
int64 weekly_pool_contribution = 6;
|
||||
bool is_expired = 7;
|
||||
google.protobuf.Timestamp calculated_at = 8;
|
||||
string date_persian = 9;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2015, Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
import "google/api/http.proto";
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "AnnotationsProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
extend google.protobuf.MethodOptions {
|
||||
// See `HttpRule`.
|
||||
HttpRule http = 72295728;
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
// Copyright 2019 Google LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
option cc_enable_arenas = true;
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "HttpProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// Defines the HTTP configuration for an API service. It contains a list of
|
||||
// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method
|
||||
// to one or more HTTP REST API methods.
|
||||
message Http {
|
||||
// A list of HTTP configuration rules that apply to individual API methods.
|
||||
//
|
||||
// **NOTE:** All service configuration rules follow "last one wins" order.
|
||||
repeated HttpRule rules = 1;
|
||||
|
||||
// When set to true, URL path parameters will be fully URI-decoded except in
|
||||
// cases of single segment matches in reserved expansion, where "%2F" will be
|
||||
// left encoded.
|
||||
//
|
||||
// The default behavior is to not decode RFC 6570 reserved characters in multi
|
||||
// segment matches.
|
||||
bool fully_decode_reserved_expansion = 2;
|
||||
}
|
||||
|
||||
// # gRPC Transcoding
|
||||
//
|
||||
// gRPC Transcoding is a feature for mapping between a gRPC method and one or
|
||||
// more HTTP REST endpoints. It allows developers to build a single API service
|
||||
// that supports both gRPC APIs and REST APIs. Many systems, including [Google
|
||||
// APIs](https://github.com/googleapis/googleapis),
|
||||
// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC
|
||||
// Gateway](https://github.com/grpc-ecosystem/grpc-gateway),
|
||||
// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature
|
||||
// and use it for large scale production services.
|
||||
//
|
||||
// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies
|
||||
// how different portions of the gRPC request message are mapped to the URL
|
||||
// path, URL query parameters, and HTTP request body. It also controls how the
|
||||
// gRPC response message is mapped to the HTTP response body. `HttpRule` is
|
||||
// typically specified as an `google.api.http` annotation on the gRPC method.
|
||||
//
|
||||
// Each mapping specifies a URL path template and an HTTP method. The path
|
||||
// template may refer to one or more fields in the gRPC request message, as long
|
||||
// as each field is a non-repeated field with a primitive (non-message) type.
|
||||
// The path template controls how fields of the request message are mapped to
|
||||
// the URL path.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get: "/v1/{name=messages/*}"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// string name = 1; // Mapped to URL path.
|
||||
// }
|
||||
// message Message {
|
||||
// string text = 1; // The resource content.
|
||||
// }
|
||||
//
|
||||
// This enables an HTTP REST to gRPC mapping as below:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")`
|
||||
//
|
||||
// Any fields in the request message which are not bound by the path template
|
||||
// automatically become HTTP query parameters if there is no HTTP request body.
|
||||
// For example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get:"/v1/messages/{message_id}"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// message SubMessage {
|
||||
// string subfield = 1;
|
||||
// }
|
||||
// string message_id = 1; // Mapped to URL path.
|
||||
// int64 revision = 2; // Mapped to URL query parameter `revision`.
|
||||
// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`.
|
||||
// }
|
||||
//
|
||||
// This enables a HTTP JSON to RPC mapping as below:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `GET /v1/messages/123456?revision=2&sub.subfield=foo` |
|
||||
// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield:
|
||||
// "foo"))`
|
||||
//
|
||||
// Note that fields which are mapped to URL query parameters must have a
|
||||
// primitive type or a repeated primitive type or a non-repeated message type.
|
||||
// In the case of a repeated type, the parameter can be repeated in the URL
|
||||
// as `...?param=A¶m=B`. In the case of a message type, each field of the
|
||||
// message is mapped to a separate parameter, such as
|
||||
// `...?foo.a=A&foo.b=B&foo.c=C`.
|
||||
//
|
||||
// For HTTP methods that allow a request body, the `body` field
|
||||
// specifies the mapping. Consider a REST update method on the
|
||||
// message resource collection:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// patch: "/v1/messages/{message_id}"
|
||||
// body: "message"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message UpdateMessageRequest {
|
||||
// string message_id = 1; // mapped to the URL
|
||||
// Message message = 2; // mapped to the body
|
||||
// }
|
||||
//
|
||||
// The following HTTP JSON to RPC mapping is enabled, where the
|
||||
// representation of the JSON in the request body is determined by
|
||||
// protos JSON encoding:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id:
|
||||
// "123456" message { text: "Hi!" })`
|
||||
//
|
||||
// The special name `*` can be used in the body mapping to define that
|
||||
// every field not bound by the path template should be mapped to the
|
||||
// request body. This enables the following alternative definition of
|
||||
// the update method:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc UpdateMessage(Message) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// patch: "/v1/messages/{message_id}"
|
||||
// body: "*"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message Message {
|
||||
// string message_id = 1;
|
||||
// string text = 2;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// The following HTTP JSON to RPC mapping is enabled:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id:
|
||||
// "123456" text: "Hi!")`
|
||||
//
|
||||
// Note that when using `*` in the body mapping, it is not possible to
|
||||
// have HTTP parameters, as all fields not bound by the path end in
|
||||
// the body. This makes this option more rarely used in practice when
|
||||
// defining REST APIs. The common usage of `*` is in custom methods
|
||||
// which don't use the URL at all for transferring data.
|
||||
//
|
||||
// It is possible to define multiple HTTP methods for one RPC by using
|
||||
// the `additional_bindings` option. Example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get: "/v1/messages/{message_id}"
|
||||
// additional_bindings {
|
||||
// get: "/v1/users/{user_id}/messages/{message_id}"
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// string message_id = 1;
|
||||
// string user_id = 2;
|
||||
// }
|
||||
//
|
||||
// This enables the following two alternative HTTP JSON to RPC mappings:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")`
|
||||
// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id:
|
||||
// "123456")`
|
||||
//
|
||||
// ## Rules for HTTP mapping
|
||||
//
|
||||
// 1. Leaf request fields (recursive expansion nested messages in the request
|
||||
// message) are classified into three categories:
|
||||
// - Fields referred by the path template. They are passed via the URL path.
|
||||
// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP
|
||||
// request body.
|
||||
// - All other fields are passed via the URL query parameters, and the
|
||||
// parameter name is the field path in the request message. A repeated
|
||||
// field can be represented as multiple query parameters under the same
|
||||
// name.
|
||||
// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields
|
||||
// are passed via URL path and HTTP request body.
|
||||
// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all
|
||||
// fields are passed via URL path and URL query parameters.
|
||||
//
|
||||
// ### Path template syntax
|
||||
//
|
||||
// Template = "/" Segments [ Verb ] ;
|
||||
// Segments = Segment { "/" Segment } ;
|
||||
// Segment = "*" | "**" | LITERAL | Variable ;
|
||||
// Variable = "{" FieldPath [ "=" Segments ] "}" ;
|
||||
// FieldPath = IDENT { "." IDENT } ;
|
||||
// Verb = ":" LITERAL ;
|
||||
//
|
||||
// The syntax `*` matches a single URL path segment. The syntax `**` matches
|
||||
// zero or more URL path segments, which must be the last part of the URL path
|
||||
// except the `Verb`.
|
||||
//
|
||||
// The syntax `Variable` matches part of the URL path as specified by its
|
||||
// template. A variable template must not contain other variables. If a variable
|
||||
// matches a single path segment, its template may be omitted, e.g. `{var}`
|
||||
// is equivalent to `{var=*}`.
|
||||
//
|
||||
// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL`
|
||||
// contains any reserved character, such characters should be percent-encoded
|
||||
// before the matching.
|
||||
//
|
||||
// If a variable contains exactly one path segment, such as `"{var}"` or
|
||||
// `"{var=*}"`, when such a variable is expanded into a URL path on the client
|
||||
// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The
|
||||
// server side does the reverse decoding. Such variables show up in the
|
||||
// [Discovery
|
||||
// Document](https://developers.google.com/discovery/v1/reference/apis) as
|
||||
// `{var}`.
|
||||
//
|
||||
// If a variable contains multiple path segments, such as `"{var=foo/*}"`
|
||||
// or `"{var=**}"`, when such a variable is expanded into a URL path on the
|
||||
// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded.
|
||||
// The server side does the reverse decoding, except "%2F" and "%2f" are left
|
||||
// unchanged. Such variables show up in the
|
||||
// [Discovery
|
||||
// Document](https://developers.google.com/discovery/v1/reference/apis) as
|
||||
// `{+var}`.
|
||||
//
|
||||
// ## Using gRPC API Service Configuration
|
||||
//
|
||||
// gRPC API Service Configuration (service config) is a configuration language
|
||||
// for configuring a gRPC service to become a user-facing product. The
|
||||
// service config is simply the YAML representation of the `google.api.Service`
|
||||
// proto message.
|
||||
//
|
||||
// As an alternative to annotating your proto file, you can configure gRPC
|
||||
// transcoding in your service config YAML files. You do this by specifying a
|
||||
// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same
|
||||
// effect as the proto annotation. This can be particularly useful if you
|
||||
// have a proto that is reused in multiple services. Note that any transcoding
|
||||
// specified in the service config will override any matching transcoding
|
||||
// configuration in the proto.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// http:
|
||||
// rules:
|
||||
// # Selects a gRPC method and applies HttpRule to it.
|
||||
// - selector: example.v1.Messaging.GetMessage
|
||||
// get: /v1/messages/{message_id}/{sub.subfield}
|
||||
//
|
||||
// ## Special notes
|
||||
//
|
||||
// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the
|
||||
// proto to JSON conversion must follow the [proto3
|
||||
// specification](https://developers.google.com/protocol-buffers/docs/proto3#json).
|
||||
//
|
||||
// While the single segment variable follows the semantics of
|
||||
// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String
|
||||
// Expansion, the multi segment variable **does not** follow RFC 6570 Section
|
||||
// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion
|
||||
// does not expand special characters like `?` and `#`, which would lead
|
||||
// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding
|
||||
// for multi segment variables.
|
||||
//
|
||||
// The path variables **must not** refer to any repeated or mapped field,
|
||||
// because client libraries are not capable of handling such variable expansion.
|
||||
//
|
||||
// The path variables **must not** capture the leading "/" character. The reason
|
||||
// is that the most common use case "{var}" does not capture the leading "/"
|
||||
// character. For consistency, all path variables must share the same behavior.
|
||||
//
|
||||
// Repeated message fields must not be mapped to URL query parameters, because
|
||||
// no client library can support such complicated mapping.
|
||||
//
|
||||
// If an API needs to use a JSON array for request or response body, it can map
|
||||
// the request or response body to a repeated field. However, some gRPC
|
||||
// Transcoding implementations may not support this feature.
|
||||
message HttpRule {
|
||||
// Selects a method to which this rule applies.
|
||||
//
|
||||
// Refer to [selector][google.api.DocumentationRule.selector] for syntax details.
|
||||
string selector = 1;
|
||||
|
||||
// Determines the URL pattern is matched by this rules. This pattern can be
|
||||
// used with any of the {get|put|post|delete|patch} methods. A custom method
|
||||
// can be defined using the 'custom' field.
|
||||
oneof pattern {
|
||||
// Maps to HTTP GET. Used for listing and getting information about
|
||||
// resources.
|
||||
string get = 2;
|
||||
|
||||
// Maps to HTTP PUT. Used for replacing a resource.
|
||||
string put = 3;
|
||||
|
||||
// Maps to HTTP POST. Used for creating a resource or performing an action.
|
||||
string post = 4;
|
||||
|
||||
// Maps to HTTP DELETE. Used for deleting a resource.
|
||||
string delete = 5;
|
||||
|
||||
// Maps to HTTP PATCH. Used for updating a resource.
|
||||
string patch = 6;
|
||||
|
||||
// The custom pattern is used for specifying an HTTP method that is not
|
||||
// included in the `pattern` field, such as HEAD, or "*" to leave the
|
||||
// HTTP method unspecified for this rule. The wild-card rule is useful
|
||||
// for services that provide content to Web (HTML) clients.
|
||||
CustomHttpPattern custom = 8;
|
||||
}
|
||||
|
||||
// The name of the request field whose value is mapped to the HTTP request
|
||||
// body, or `*` for mapping all request fields not captured by the path
|
||||
// pattern to the HTTP body, or omitted for not having any HTTP request body.
|
||||
//
|
||||
// NOTE: the referred field must be present at the top-level of the request
|
||||
// message type.
|
||||
string body = 7;
|
||||
|
||||
// Optional. The name of the response field whose value is mapped to the HTTP
|
||||
// response body. When omitted, the entire response message will be used
|
||||
// as the HTTP response body.
|
||||
//
|
||||
// NOTE: The referred field must be present at the top-level of the response
|
||||
// message type.
|
||||
string response_body = 12;
|
||||
|
||||
// Additional HTTP bindings for the selector. Nested bindings must
|
||||
// not contain an `additional_bindings` field themselves (that is,
|
||||
// the nesting may only be one level deep).
|
||||
repeated HttpRule additional_bindings = 11;
|
||||
}
|
||||
|
||||
// A custom pattern is used for defining custom HTTP verb.
|
||||
message CustomHttpPattern {
|
||||
// The name of this custom HTTP verb.
|
||||
string kind = 1;
|
||||
|
||||
// The path matched by this custom verb.
|
||||
string path = 2;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using FluentValidation;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
public static class ConfigureServices
|
||||
{
|
||||
public static IServiceCollection AddDiscountShopProtobufServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>0.0.1</Version>
|
||||
<PackageId>Foursat.FrontOffice.BFF.DiscountShop.Protobuf</PackageId>
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<DebugSymbols>False</DebugSymbols>
|
||||
<DebugType>None</DebugType>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.23.3" />
|
||||
<PackageReference Include="Grpc.Core.Api" Version="2.54.0" />
|
||||
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.2.2" />
|
||||
<PackageReference Include="Google.Api.CommonProtos" Version="2.10.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.55.1" >
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Protobuf Include="Protos\discountshop.proto" ProtoRoot="Protos\" GrpcServices="Both" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,190 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package discountshop;
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
import "google/protobuf/wrappers.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "google/api/annotations.proto";
|
||||
|
||||
option csharp_namespace = "FrontOffice.BFF.DiscountShop.Protobuf.Protos.DiscountShop";
|
||||
|
||||
// سرویس فروشگاه تخفیفی - برای کاربران عضو باشگاه
|
||||
service DiscountShopContract
|
||||
{
|
||||
// محصولات
|
||||
rpc GetDiscountProducts(GetDiscountProductsRequest) returns (GetDiscountProductsResponse){
|
||||
option (google.api.http) = {
|
||||
get: "/DiscountShop/Products"
|
||||
};
|
||||
};
|
||||
|
||||
// دستهبندیها
|
||||
rpc GetDiscountCategories(GetDiscountCategoriesRequest) returns (GetDiscountCategoriesResponse){
|
||||
option (google.api.http) = {
|
||||
get: "/DiscountShop/Categories"
|
||||
};
|
||||
};
|
||||
|
||||
// سبد خرید
|
||||
rpc GetMyDiscountCart(google.protobuf.Empty) returns (GetMyDiscountCartResponse){
|
||||
option (google.api.http) = {
|
||||
get: "/DiscountShop/Cart"
|
||||
};
|
||||
};
|
||||
|
||||
rpc AddToDiscountCart(AddToDiscountCartRequest) returns (google.protobuf.Empty){
|
||||
option (google.api.http) = {
|
||||
post: "/DiscountShop/Cart/Add"
|
||||
body: "*"
|
||||
};
|
||||
};
|
||||
|
||||
rpc RemoveFromDiscountCart(RemoveFromDiscountCartRequest) returns (google.protobuf.Empty){
|
||||
option (google.api.http) = {
|
||||
post: "/DiscountShop/Cart/Remove"
|
||||
body: "*"
|
||||
};
|
||||
};
|
||||
|
||||
// سفارشات
|
||||
rpc GetMyDiscountOrders(GetMyDiscountOrdersRequest) returns (GetMyDiscountOrdersResponse){
|
||||
option (google.api.http) = {
|
||||
get: "/DiscountShop/Orders"
|
||||
};
|
||||
};
|
||||
|
||||
rpc PlaceDiscountOrder(PlaceDiscountOrderRequest) returns (PlaceDiscountOrderResponse){
|
||||
option (google.api.http) = {
|
||||
post: "/DiscountShop/Orders/Place"
|
||||
body: "*"
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// ============ MetaData ============
|
||||
message MetaData
|
||||
{
|
||||
int64 total_count = 1;
|
||||
}
|
||||
|
||||
// ============ Products ============
|
||||
message GetDiscountProductsRequest
|
||||
{
|
||||
int32 page_number = 1;
|
||||
int32 page_size = 2;
|
||||
google.protobuf.StringValue search_term = 3;
|
||||
google.protobuf.Int64Value category_id = 4;
|
||||
}
|
||||
|
||||
message GetDiscountProductsResponse
|
||||
{
|
||||
MetaData meta_data = 1;
|
||||
repeated DiscountProductModel products = 2;
|
||||
}
|
||||
|
||||
message DiscountProductModel
|
||||
{
|
||||
int64 id = 1;
|
||||
string title = 2;
|
||||
string description = 3;
|
||||
string image_path = 4;
|
||||
int64 original_price = 5;
|
||||
int64 discounted_price = 6;
|
||||
int32 discount_percent = 7;
|
||||
int32 remaining_count = 8;
|
||||
bool is_available = 9;
|
||||
}
|
||||
|
||||
// ============ Categories ============
|
||||
message GetDiscountCategoriesRequest
|
||||
{
|
||||
google.protobuf.Int64Value parent_category_id = 1;
|
||||
bool only_active = 2;
|
||||
}
|
||||
|
||||
message GetDiscountCategoriesResponse
|
||||
{
|
||||
repeated DiscountCategoryModel categories = 1;
|
||||
}
|
||||
|
||||
message DiscountCategoryModel
|
||||
{
|
||||
int64 id = 1;
|
||||
string title = 2;
|
||||
google.protobuf.Int64Value parent_id = 3;
|
||||
string icon_path = 4;
|
||||
int32 sort_order = 5;
|
||||
repeated DiscountCategoryModel children = 6;
|
||||
}
|
||||
|
||||
// ============ Cart ============
|
||||
message GetMyDiscountCartResponse
|
||||
{
|
||||
repeated DiscountCartItemModel items = 1;
|
||||
int64 total_price = 2;
|
||||
int64 total_discount_amount = 3;
|
||||
}
|
||||
|
||||
message DiscountCartItemModel
|
||||
{
|
||||
int64 product_id = 1;
|
||||
string product_title = 2;
|
||||
string product_image_path = 3;
|
||||
int64 unit_price = 4;
|
||||
int32 count = 5;
|
||||
int64 total_price = 6;
|
||||
}
|
||||
|
||||
message AddToDiscountCartRequest
|
||||
{
|
||||
int64 product_id = 1;
|
||||
int32 count = 2;
|
||||
}
|
||||
|
||||
message RemoveFromDiscountCartRequest
|
||||
{
|
||||
int64 product_id = 1;
|
||||
}
|
||||
|
||||
// ============ Orders ============
|
||||
message GetMyDiscountOrdersRequest
|
||||
{
|
||||
int32 page_number = 1;
|
||||
int32 page_size = 2;
|
||||
}
|
||||
|
||||
message GetMyDiscountOrdersResponse
|
||||
{
|
||||
MetaData meta_data = 1;
|
||||
repeated DiscountOrderModel orders = 2;
|
||||
}
|
||||
|
||||
message DiscountOrderModel
|
||||
{
|
||||
int64 id = 1;
|
||||
string order_number = 2;
|
||||
string status = 3;
|
||||
string status_color = 4;
|
||||
int64 total_amount = 5;
|
||||
int64 discount_used = 6;
|
||||
int64 gateway_paid = 7;
|
||||
google.protobuf.Timestamp created_at = 8;
|
||||
string created_at_persian = 9;
|
||||
}
|
||||
|
||||
message PlaceDiscountOrderRequest
|
||||
{
|
||||
int64 user_address_id = 1;
|
||||
int64 discount_balance_to_use = 2;
|
||||
google.protobuf.StringValue notes = 3;
|
||||
}
|
||||
|
||||
message PlaceDiscountOrderResponse
|
||||
{
|
||||
bool success = 1;
|
||||
string message = 2;
|
||||
int64 order_id = 3;
|
||||
string order_number = 4;
|
||||
google.protobuf.StringValue payment_url = 5;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2015, Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
import "google/api/http.proto";
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "AnnotationsProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
extend google.protobuf.MethodOptions {
|
||||
// See `HttpRule`.
|
||||
HttpRule http = 72295728;
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
// Copyright 2019 Google LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
option cc_enable_arenas = true;
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "HttpProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// Defines the HTTP configuration for an API service. It contains a list of
|
||||
// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method
|
||||
// to one or more HTTP REST API methods.
|
||||
message Http {
|
||||
// A list of HTTP configuration rules that apply to individual API methods.
|
||||
//
|
||||
// **NOTE:** All service configuration rules follow "last one wins" order.
|
||||
repeated HttpRule rules = 1;
|
||||
|
||||
// When set to true, URL path parameters will be fully URI-decoded except in
|
||||
// cases of single segment matches in reserved expansion, where "%2F" will be
|
||||
// left encoded.
|
||||
//
|
||||
// The default behavior is to not decode RFC 6570 reserved characters in multi
|
||||
// segment matches.
|
||||
bool fully_decode_reserved_expansion = 2;
|
||||
}
|
||||
|
||||
// # gRPC Transcoding
|
||||
//
|
||||
// gRPC Transcoding is a feature for mapping between a gRPC method and one or
|
||||
// more HTTP REST endpoints. It allows developers to build a single API service
|
||||
// that supports both gRPC APIs and REST APIs. Many systems, including [Google
|
||||
// APIs](https://github.com/googleapis/googleapis),
|
||||
// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC
|
||||
// Gateway](https://github.com/grpc-ecosystem/grpc-gateway),
|
||||
// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature
|
||||
// and use it for large scale production services.
|
||||
//
|
||||
// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies
|
||||
// how different portions of the gRPC request message are mapped to the URL
|
||||
// path, URL query parameters, and HTTP request body. It also controls how the
|
||||
// gRPC response message is mapped to the HTTP response body. `HttpRule` is
|
||||
// typically specified as an `google.api.http` annotation on the gRPC method.
|
||||
//
|
||||
// Each mapping specifies a URL path template and an HTTP method. The path
|
||||
// template may refer to one or more fields in the gRPC request message, as long
|
||||
// as each field is a non-repeated field with a primitive (non-message) type.
|
||||
// The path template controls how fields of the request message are mapped to
|
||||
// the URL path.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get: "/v1/{name=messages/*}"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// string name = 1; // Mapped to URL path.
|
||||
// }
|
||||
// message Message {
|
||||
// string text = 1; // The resource content.
|
||||
// }
|
||||
//
|
||||
// This enables an HTTP REST to gRPC mapping as below:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")`
|
||||
//
|
||||
// Any fields in the request message which are not bound by the path template
|
||||
// automatically become HTTP query parameters if there is no HTTP request body.
|
||||
// For example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get:"/v1/messages/{message_id}"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// message SubMessage {
|
||||
// string subfield = 1;
|
||||
// }
|
||||
// string message_id = 1; // Mapped to URL path.
|
||||
// int64 revision = 2; // Mapped to URL query parameter `revision`.
|
||||
// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`.
|
||||
// }
|
||||
//
|
||||
// This enables a HTTP JSON to RPC mapping as below:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `GET /v1/messages/123456?revision=2&sub.subfield=foo` |
|
||||
// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield:
|
||||
// "foo"))`
|
||||
//
|
||||
// Note that fields which are mapped to URL query parameters must have a
|
||||
// primitive type or a repeated primitive type or a non-repeated message type.
|
||||
// In the case of a repeated type, the parameter can be repeated in the URL
|
||||
// as `...?param=A¶m=B`. In the case of a message type, each field of the
|
||||
// message is mapped to a separate parameter, such as
|
||||
// `...?foo.a=A&foo.b=B&foo.c=C`.
|
||||
//
|
||||
// For HTTP methods that allow a request body, the `body` field
|
||||
// specifies the mapping. Consider a REST update method on the
|
||||
// message resource collection:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// patch: "/v1/messages/{message_id}"
|
||||
// body: "message"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message UpdateMessageRequest {
|
||||
// string message_id = 1; // mapped to the URL
|
||||
// Message message = 2; // mapped to the body
|
||||
// }
|
||||
//
|
||||
// The following HTTP JSON to RPC mapping is enabled, where the
|
||||
// representation of the JSON in the request body is determined by
|
||||
// protos JSON encoding:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id:
|
||||
// "123456" message { text: "Hi!" })`
|
||||
//
|
||||
// The special name `*` can be used in the body mapping to define that
|
||||
// every field not bound by the path template should be mapped to the
|
||||
// request body. This enables the following alternative definition of
|
||||
// the update method:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc UpdateMessage(Message) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// patch: "/v1/messages/{message_id}"
|
||||
// body: "*"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message Message {
|
||||
// string message_id = 1;
|
||||
// string text = 2;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// The following HTTP JSON to RPC mapping is enabled:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id:
|
||||
// "123456" text: "Hi!")`
|
||||
//
|
||||
// Note that when using `*` in the body mapping, it is not possible to
|
||||
// have HTTP parameters, as all fields not bound by the path end in
|
||||
// the body. This makes this option more rarely used in practice when
|
||||
// defining REST APIs. The common usage of `*` is in custom methods
|
||||
// which don't use the URL at all for transferring data.
|
||||
//
|
||||
// It is possible to define multiple HTTP methods for one RPC by using
|
||||
// the `additional_bindings` option. Example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get: "/v1/messages/{message_id}"
|
||||
// additional_bindings {
|
||||
// get: "/v1/users/{user_id}/messages/{message_id}"
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// string message_id = 1;
|
||||
// string user_id = 2;
|
||||
// }
|
||||
//
|
||||
// This enables the following two alternative HTTP JSON to RPC mappings:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")`
|
||||
// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id:
|
||||
// "123456")`
|
||||
//
|
||||
// ## Rules for HTTP mapping
|
||||
//
|
||||
// 1. Leaf request fields (recursive expansion nested messages in the request
|
||||
// message) are classified into three categories:
|
||||
// - Fields referred by the path template. They are passed via the URL path.
|
||||
// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP
|
||||
// request body.
|
||||
// - All other fields are passed via the URL query parameters, and the
|
||||
// parameter name is the field path in the request message. A repeated
|
||||
// field can be represented as multiple query parameters under the same
|
||||
// name.
|
||||
// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields
|
||||
// are passed via URL path and HTTP request body.
|
||||
// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all
|
||||
// fields are passed via URL path and URL query parameters.
|
||||
//
|
||||
// ### Path template syntax
|
||||
//
|
||||
// Template = "/" Segments [ Verb ] ;
|
||||
// Segments = Segment { "/" Segment } ;
|
||||
// Segment = "*" | "**" | LITERAL | Variable ;
|
||||
// Variable = "{" FieldPath [ "=" Segments ] "}" ;
|
||||
// FieldPath = IDENT { "." IDENT } ;
|
||||
// Verb = ":" LITERAL ;
|
||||
//
|
||||
// The syntax `*` matches a single URL path segment. The syntax `**` matches
|
||||
// zero or more URL path segments, which must be the last part of the URL path
|
||||
// except the `Verb`.
|
||||
//
|
||||
// The syntax `Variable` matches part of the URL path as specified by its
|
||||
// template. A variable template must not contain other variables. If a variable
|
||||
// matches a single path segment, its template may be omitted, e.g. `{var}`
|
||||
// is equivalent to `{var=*}`.
|
||||
//
|
||||
// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL`
|
||||
// contains any reserved character, such characters should be percent-encoded
|
||||
// before the matching.
|
||||
//
|
||||
// If a variable contains exactly one path segment, such as `"{var}"` or
|
||||
// `"{var=*}"`, when such a variable is expanded into a URL path on the client
|
||||
// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The
|
||||
// server side does the reverse decoding. Such variables show up in the
|
||||
// [Discovery
|
||||
// Document](https://developers.google.com/discovery/v1/reference/apis) as
|
||||
// `{var}`.
|
||||
//
|
||||
// If a variable contains multiple path segments, such as `"{var=foo/*}"`
|
||||
// or `"{var=**}"`, when such a variable is expanded into a URL path on the
|
||||
// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded.
|
||||
// The server side does the reverse decoding, except "%2F" and "%2f" are left
|
||||
// unchanged. Such variables show up in the
|
||||
// [Discovery
|
||||
// Document](https://developers.google.com/discovery/v1/reference/apis) as
|
||||
// `{+var}`.
|
||||
//
|
||||
// ## Using gRPC API Service Configuration
|
||||
//
|
||||
// gRPC API Service Configuration (service config) is a configuration language
|
||||
// for configuring a gRPC service to become a user-facing product. The
|
||||
// service config is simply the YAML representation of the `google.api.Service`
|
||||
// proto message.
|
||||
//
|
||||
// As an alternative to annotating your proto file, you can configure gRPC
|
||||
// transcoding in your service config YAML files. You do this by specifying a
|
||||
// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same
|
||||
// effect as the proto annotation. This can be particularly useful if you
|
||||
// have a proto that is reused in multiple services. Note that any transcoding
|
||||
// specified in the service config will override any matching transcoding
|
||||
// configuration in the proto.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// http:
|
||||
// rules:
|
||||
// # Selects a gRPC method and applies HttpRule to it.
|
||||
// - selector: example.v1.Messaging.GetMessage
|
||||
// get: /v1/messages/{message_id}/{sub.subfield}
|
||||
//
|
||||
// ## Special notes
|
||||
//
|
||||
// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the
|
||||
// proto to JSON conversion must follow the [proto3
|
||||
// specification](https://developers.google.com/protocol-buffers/docs/proto3#json).
|
||||
//
|
||||
// While the single segment variable follows the semantics of
|
||||
// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String
|
||||
// Expansion, the multi segment variable **does not** follow RFC 6570 Section
|
||||
// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion
|
||||
// does not expand special characters like `?` and `#`, which would lead
|
||||
// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding
|
||||
// for multi segment variables.
|
||||
//
|
||||
// The path variables **must not** refer to any repeated or mapped field,
|
||||
// because client libraries are not capable of handling such variable expansion.
|
||||
//
|
||||
// The path variables **must not** capture the leading "/" character. The reason
|
||||
// is that the most common use case "{var}" does not capture the leading "/"
|
||||
// character. For consistency, all path variables must share the same behavior.
|
||||
//
|
||||
// Repeated message fields must not be mapped to URL query parameters, because
|
||||
// no client library can support such complicated mapping.
|
||||
//
|
||||
// If an API needs to use a JSON array for request or response body, it can map
|
||||
// the request or response body to a repeated field. However, some gRPC
|
||||
// Transcoding implementations may not support this feature.
|
||||
message HttpRule {
|
||||
// Selects a method to which this rule applies.
|
||||
//
|
||||
// Refer to [selector][google.api.DocumentationRule.selector] for syntax details.
|
||||
string selector = 1;
|
||||
|
||||
// Determines the URL pattern is matched by this rules. This pattern can be
|
||||
// used with any of the {get|put|post|delete|patch} methods. A custom method
|
||||
// can be defined using the 'custom' field.
|
||||
oneof pattern {
|
||||
// Maps to HTTP GET. Used for listing and getting information about
|
||||
// resources.
|
||||
string get = 2;
|
||||
|
||||
// Maps to HTTP PUT. Used for replacing a resource.
|
||||
string put = 3;
|
||||
|
||||
// Maps to HTTP POST. Used for creating a resource or performing an action.
|
||||
string post = 4;
|
||||
|
||||
// Maps to HTTP DELETE. Used for deleting a resource.
|
||||
string delete = 5;
|
||||
|
||||
// Maps to HTTP PATCH. Used for updating a resource.
|
||||
string patch = 6;
|
||||
|
||||
// The custom pattern is used for specifying an HTTP method that is not
|
||||
// included in the `pattern` field, such as HEAD, or "*" to leave the
|
||||
// HTTP method unspecified for this rule. The wild-card rule is useful
|
||||
// for services that provide content to Web (HTML) clients.
|
||||
CustomHttpPattern custom = 8;
|
||||
}
|
||||
|
||||
// The name of the request field whose value is mapped to the HTTP request
|
||||
// body, or `*` for mapping all request fields not captured by the path
|
||||
// pattern to the HTTP body, or omitted for not having any HTTP request body.
|
||||
//
|
||||
// NOTE: the referred field must be present at the top-level of the request
|
||||
// message type.
|
||||
string body = 7;
|
||||
|
||||
// Optional. The name of the response field whose value is mapped to the HTTP
|
||||
// response body. When omitted, the entire response message will be used
|
||||
// as the HTTP response body.
|
||||
//
|
||||
// NOTE: The referred field must be present at the top-level of the response
|
||||
// message type.
|
||||
string response_body = 12;
|
||||
|
||||
// Additional HTTP bindings for the selector. Nested bindings must
|
||||
// not contain an `additional_bindings` field themselves (that is,
|
||||
// the nesting may only be one level deep).
|
||||
repeated HttpRule additional_bindings = 11;
|
||||
}
|
||||
|
||||
// A custom pattern is used for defining custom HTTP verb.
|
||||
message CustomHttpPattern {
|
||||
// The name of this custom HTTP verb.
|
||||
string kind = 1;
|
||||
|
||||
// The path matched by this custom verb.
|
||||
string path = 2;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using FluentValidation;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
public static class ConfigureServices
|
||||
{
|
||||
public static IServiceCollection AddNetworkMembershipProtobufServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>0.0.1</Version>
|
||||
<PackageId>Foursat.FrontOffice.BFF.NetworkMembership.Protobuf</PackageId>
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<DebugSymbols>False</DebugSymbols>
|
||||
<DebugType>None</DebugType>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.23.3" />
|
||||
<PackageReference Include="Grpc.Core.Api" Version="2.54.0" />
|
||||
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.2.2" />
|
||||
<PackageReference Include="Google.Api.CommonProtos" Version="2.10.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.55.1" >
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Protobuf Include="Protos\networkmembership.proto" ProtoRoot="Protos\" GrpcServices="Both" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2015, Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
import "google/api/http.proto";
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "AnnotationsProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
extend google.protobuf.MethodOptions {
|
||||
// See `HttpRule`.
|
||||
HttpRule http = 72295728;
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
// Copyright 2019 Google LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
option cc_enable_arenas = true;
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "HttpProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// Defines the HTTP configuration for an API service. It contains a list of
|
||||
// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method
|
||||
// to one or more HTTP REST API methods.
|
||||
message Http {
|
||||
// A list of HTTP configuration rules that apply to individual API methods.
|
||||
//
|
||||
// **NOTE:** All service configuration rules follow "last one wins" order.
|
||||
repeated HttpRule rules = 1;
|
||||
|
||||
// When set to true, URL path parameters will be fully URI-decoded except in
|
||||
// cases of single segment matches in reserved expansion, where "%2F" will be
|
||||
// left encoded.
|
||||
//
|
||||
// The default behavior is to not decode RFC 6570 reserved characters in multi
|
||||
// segment matches.
|
||||
bool fully_decode_reserved_expansion = 2;
|
||||
}
|
||||
|
||||
// # gRPC Transcoding
|
||||
//
|
||||
// gRPC Transcoding is a feature for mapping between a gRPC method and one or
|
||||
// more HTTP REST endpoints. It allows developers to build a single API service
|
||||
// that supports both gRPC APIs and REST APIs. Many systems, including [Google
|
||||
// APIs](https://github.com/googleapis/googleapis),
|
||||
// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC
|
||||
// Gateway](https://github.com/grpc-ecosystem/grpc-gateway),
|
||||
// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature
|
||||
// and use it for large scale production services.
|
||||
//
|
||||
// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies
|
||||
// how different portions of the gRPC request message are mapped to the URL
|
||||
// path, URL query parameters, and HTTP request body. It also controls how the
|
||||
// gRPC response message is mapped to the HTTP response body. `HttpRule` is
|
||||
// typically specified as an `google.api.http` annotation on the gRPC method.
|
||||
//
|
||||
// Each mapping specifies a URL path template and an HTTP method. The path
|
||||
// template may refer to one or more fields in the gRPC request message, as long
|
||||
// as each field is a non-repeated field with a primitive (non-message) type.
|
||||
// The path template controls how fields of the request message are mapped to
|
||||
// the URL path.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get: "/v1/{name=messages/*}"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// string name = 1; // Mapped to URL path.
|
||||
// }
|
||||
// message Message {
|
||||
// string text = 1; // The resource content.
|
||||
// }
|
||||
//
|
||||
// This enables an HTTP REST to gRPC mapping as below:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")`
|
||||
//
|
||||
// Any fields in the request message which are not bound by the path template
|
||||
// automatically become HTTP query parameters if there is no HTTP request body.
|
||||
// For example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get:"/v1/messages/{message_id}"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// message SubMessage {
|
||||
// string subfield = 1;
|
||||
// }
|
||||
// string message_id = 1; // Mapped to URL path.
|
||||
// int64 revision = 2; // Mapped to URL query parameter `revision`.
|
||||
// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`.
|
||||
// }
|
||||
//
|
||||
// This enables a HTTP JSON to RPC mapping as below:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `GET /v1/messages/123456?revision=2&sub.subfield=foo` |
|
||||
// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield:
|
||||
// "foo"))`
|
||||
//
|
||||
// Note that fields which are mapped to URL query parameters must have a
|
||||
// primitive type or a repeated primitive type or a non-repeated message type.
|
||||
// In the case of a repeated type, the parameter can be repeated in the URL
|
||||
// as `...?param=A¶m=B`. In the case of a message type, each field of the
|
||||
// message is mapped to a separate parameter, such as
|
||||
// `...?foo.a=A&foo.b=B&foo.c=C`.
|
||||
//
|
||||
// For HTTP methods that allow a request body, the `body` field
|
||||
// specifies the mapping. Consider a REST update method on the
|
||||
// message resource collection:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// patch: "/v1/messages/{message_id}"
|
||||
// body: "message"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message UpdateMessageRequest {
|
||||
// string message_id = 1; // mapped to the URL
|
||||
// Message message = 2; // mapped to the body
|
||||
// }
|
||||
//
|
||||
// The following HTTP JSON to RPC mapping is enabled, where the
|
||||
// representation of the JSON in the request body is determined by
|
||||
// protos JSON encoding:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id:
|
||||
// "123456" message { text: "Hi!" })`
|
||||
//
|
||||
// The special name `*` can be used in the body mapping to define that
|
||||
// every field not bound by the path template should be mapped to the
|
||||
// request body. This enables the following alternative definition of
|
||||
// the update method:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc UpdateMessage(Message) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// patch: "/v1/messages/{message_id}"
|
||||
// body: "*"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message Message {
|
||||
// string message_id = 1;
|
||||
// string text = 2;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// The following HTTP JSON to RPC mapping is enabled:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id:
|
||||
// "123456" text: "Hi!")`
|
||||
//
|
||||
// Note that when using `*` in the body mapping, it is not possible to
|
||||
// have HTTP parameters, as all fields not bound by the path end in
|
||||
// the body. This makes this option more rarely used in practice when
|
||||
// defining REST APIs. The common usage of `*` is in custom methods
|
||||
// which don't use the URL at all for transferring data.
|
||||
//
|
||||
// It is possible to define multiple HTTP methods for one RPC by using
|
||||
// the `additional_bindings` option. Example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get: "/v1/messages/{message_id}"
|
||||
// additional_bindings {
|
||||
// get: "/v1/users/{user_id}/messages/{message_id}"
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// string message_id = 1;
|
||||
// string user_id = 2;
|
||||
// }
|
||||
//
|
||||
// This enables the following two alternative HTTP JSON to RPC mappings:
|
||||
//
|
||||
// HTTP | gRPC
|
||||
// -----|-----
|
||||
// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")`
|
||||
// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id:
|
||||
// "123456")`
|
||||
//
|
||||
// ## Rules for HTTP mapping
|
||||
//
|
||||
// 1. Leaf request fields (recursive expansion nested messages in the request
|
||||
// message) are classified into three categories:
|
||||
// - Fields referred by the path template. They are passed via the URL path.
|
||||
// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP
|
||||
// request body.
|
||||
// - All other fields are passed via the URL query parameters, and the
|
||||
// parameter name is the field path in the request message. A repeated
|
||||
// field can be represented as multiple query parameters under the same
|
||||
// name.
|
||||
// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields
|
||||
// are passed via URL path and HTTP request body.
|
||||
// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all
|
||||
// fields are passed via URL path and URL query parameters.
|
||||
//
|
||||
// ### Path template syntax
|
||||
//
|
||||
// Template = "/" Segments [ Verb ] ;
|
||||
// Segments = Segment { "/" Segment } ;
|
||||
// Segment = "*" | "**" | LITERAL | Variable ;
|
||||
// Variable = "{" FieldPath [ "=" Segments ] "}" ;
|
||||
// FieldPath = IDENT { "." IDENT } ;
|
||||
// Verb = ":" LITERAL ;
|
||||
//
|
||||
// The syntax `*` matches a single URL path segment. The syntax `**` matches
|
||||
// zero or more URL path segments, which must be the last part of the URL path
|
||||
// except the `Verb`.
|
||||
//
|
||||
// The syntax `Variable` matches part of the URL path as specified by its
|
||||
// template. A variable template must not contain other variables. If a variable
|
||||
// matches a single path segment, its template may be omitted, e.g. `{var}`
|
||||
// is equivalent to `{var=*}`.
|
||||
//
|
||||
// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL`
|
||||
// contains any reserved character, such characters should be percent-encoded
|
||||
// before the matching.
|
||||
//
|
||||
// If a variable contains exactly one path segment, such as `"{var}"` or
|
||||
// `"{var=*}"`, when such a variable is expanded into a URL path on the client
|
||||
// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The
|
||||
// server side does the reverse decoding. Such variables show up in the
|
||||
// [Discovery
|
||||
// Document](https://developers.google.com/discovery/v1/reference/apis) as
|
||||
// `{var}`.
|
||||
//
|
||||
// If a variable contains multiple path segments, such as `"{var=foo/*}"`
|
||||
// or `"{var=**}"`, when such a variable is expanded into a URL path on the
|
||||
// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded.
|
||||
// The server side does the reverse decoding, except "%2F" and "%2f" are left
|
||||
// unchanged. Such variables show up in the
|
||||
// [Discovery
|
||||
// Document](https://developers.google.com/discovery/v1/reference/apis) as
|
||||
// `{+var}`.
|
||||
//
|
||||
// ## Using gRPC API Service Configuration
|
||||
//
|
||||
// gRPC API Service Configuration (service config) is a configuration language
|
||||
// for configuring a gRPC service to become a user-facing product. The
|
||||
// service config is simply the YAML representation of the `google.api.Service`
|
||||
// proto message.
|
||||
//
|
||||
// As an alternative to annotating your proto file, you can configure gRPC
|
||||
// transcoding in your service config YAML files. You do this by specifying a
|
||||
// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same
|
||||
// effect as the proto annotation. This can be particularly useful if you
|
||||
// have a proto that is reused in multiple services. Note that any transcoding
|
||||
// specified in the service config will override any matching transcoding
|
||||
// configuration in the proto.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// http:
|
||||
// rules:
|
||||
// # Selects a gRPC method and applies HttpRule to it.
|
||||
// - selector: example.v1.Messaging.GetMessage
|
||||
// get: /v1/messages/{message_id}/{sub.subfield}
|
||||
//
|
||||
// ## Special notes
|
||||
//
|
||||
// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the
|
||||
// proto to JSON conversion must follow the [proto3
|
||||
// specification](https://developers.google.com/protocol-buffers/docs/proto3#json).
|
||||
//
|
||||
// While the single segment variable follows the semantics of
|
||||
// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String
|
||||
// Expansion, the multi segment variable **does not** follow RFC 6570 Section
|
||||
// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion
|
||||
// does not expand special characters like `?` and `#`, which would lead
|
||||
// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding
|
||||
// for multi segment variables.
|
||||
//
|
||||
// The path variables **must not** refer to any repeated or mapped field,
|
||||
// because client libraries are not capable of handling such variable expansion.
|
||||
//
|
||||
// The path variables **must not** capture the leading "/" character. The reason
|
||||
// is that the most common use case "{var}" does not capture the leading "/"
|
||||
// character. For consistency, all path variables must share the same behavior.
|
||||
//
|
||||
// Repeated message fields must not be mapped to URL query parameters, because
|
||||
// no client library can support such complicated mapping.
|
||||
//
|
||||
// If an API needs to use a JSON array for request or response body, it can map
|
||||
// the request or response body to a repeated field. However, some gRPC
|
||||
// Transcoding implementations may not support this feature.
|
||||
message HttpRule {
|
||||
// Selects a method to which this rule applies.
|
||||
//
|
||||
// Refer to [selector][google.api.DocumentationRule.selector] for syntax details.
|
||||
string selector = 1;
|
||||
|
||||
// Determines the URL pattern is matched by this rules. This pattern can be
|
||||
// used with any of the {get|put|post|delete|patch} methods. A custom method
|
||||
// can be defined using the 'custom' field.
|
||||
oneof pattern {
|
||||
// Maps to HTTP GET. Used for listing and getting information about
|
||||
// resources.
|
||||
string get = 2;
|
||||
|
||||
// Maps to HTTP PUT. Used for replacing a resource.
|
||||
string put = 3;
|
||||
|
||||
// Maps to HTTP POST. Used for creating a resource or performing an action.
|
||||
string post = 4;
|
||||
|
||||
// Maps to HTTP DELETE. Used for deleting a resource.
|
||||
string delete = 5;
|
||||
|
||||
// Maps to HTTP PATCH. Used for updating a resource.
|
||||
string patch = 6;
|
||||
|
||||
// The custom pattern is used for specifying an HTTP method that is not
|
||||
// included in the `pattern` field, such as HEAD, or "*" to leave the
|
||||
// HTTP method unspecified for this rule. The wild-card rule is useful
|
||||
// for services that provide content to Web (HTML) clients.
|
||||
CustomHttpPattern custom = 8;
|
||||
}
|
||||
|
||||
// The name of the request field whose value is mapped to the HTTP request
|
||||
// body, or `*` for mapping all request fields not captured by the path
|
||||
// pattern to the HTTP body, or omitted for not having any HTTP request body.
|
||||
//
|
||||
// NOTE: the referred field must be present at the top-level of the request
|
||||
// message type.
|
||||
string body = 7;
|
||||
|
||||
// Optional. The name of the response field whose value is mapped to the HTTP
|
||||
// response body. When omitted, the entire response message will be used
|
||||
// as the HTTP response body.
|
||||
//
|
||||
// NOTE: The referred field must be present at the top-level of the response
|
||||
// message type.
|
||||
string response_body = 12;
|
||||
|
||||
// Additional HTTP bindings for the selector. Nested bindings must
|
||||
// not contain an `additional_bindings` field themselves (that is,
|
||||
// the nesting may only be one level deep).
|
||||
repeated HttpRule additional_bindings = 11;
|
||||
}
|
||||
|
||||
// A custom pattern is used for defining custom HTTP verb.
|
||||
message CustomHttpPattern {
|
||||
// The name of this custom HTTP verb.
|
||||
string kind = 1;
|
||||
|
||||
// The path matched by this custom verb.
|
||||
string path = 2;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package networkmembership;
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
import "google/protobuf/wrappers.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "google/api/annotations.proto";
|
||||
|
||||
option csharp_namespace = "FrontOffice.BFF.NetworkMembership.Protobuf.Protos.NetworkMembership";
|
||||
|
||||
// سرویس عضویت شبکهای - برای کاربران FrontOffice
|
||||
service NetworkMembershipContract
|
||||
{
|
||||
// دریافت درخت شبکه کاربر جاری
|
||||
rpc GetMyNetworkTree(GetMyNetworkTreeRequest) returns (GetMyNetworkTreeResponse){
|
||||
option (google.api.http) = {
|
||||
get: "/NetworkMembership/MyTree"
|
||||
};
|
||||
};
|
||||
|
||||
// دریافت آمار شبکه کاربر جاری
|
||||
rpc GetMyNetworkStatistics(google.protobuf.Empty) returns (GetMyNetworkStatisticsResponse){
|
||||
option (google.api.http) = {
|
||||
get: "/NetworkMembership/MyStats"
|
||||
};
|
||||
};
|
||||
|
||||
// دریافت موقعیت کاربر در شبکه
|
||||
rpc GetMyNetworkPosition(google.protobuf.Empty) returns (GetMyNetworkPositionResponse){
|
||||
option (google.api.http) = {
|
||||
get: "/NetworkMembership/MyPosition"
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// ============ GetMyNetworkTree ============
|
||||
message GetMyNetworkTreeRequest
|
||||
{
|
||||
int32 max_depth = 1; // حداکثر عمق درخت (پیشفرض: 3)
|
||||
}
|
||||
|
||||
message GetMyNetworkTreeResponse
|
||||
{
|
||||
NetworkNodeModel root_node = 1;
|
||||
int32 total_members = 2;
|
||||
int32 current_depth = 3;
|
||||
}
|
||||
|
||||
message NetworkNodeModel
|
||||
{
|
||||
int64 user_id = 1;
|
||||
string full_name = 2;
|
||||
string mobile = 3;
|
||||
google.protobuf.StringValue avatar = 4;
|
||||
string position = 5; // Root/Left/Right
|
||||
NetworkNodeModel left_child = 6;
|
||||
NetworkNodeModel right_child = 7;
|
||||
int32 level = 8;
|
||||
bool has_children = 9;
|
||||
}
|
||||
|
||||
// ============ GetMyNetworkStatistics ============
|
||||
message GetMyNetworkStatisticsResponse
|
||||
{
|
||||
int32 total_members = 1;
|
||||
int32 active_members = 2;
|
||||
int32 left_leg_count = 3;
|
||||
int32 right_leg_count = 4;
|
||||
double left_percentage = 5;
|
||||
double right_percentage = 6;
|
||||
double average_depth = 7;
|
||||
int32 max_depth = 8;
|
||||
string weaker_leg = 9;
|
||||
int32 my_network_level = 10;
|
||||
string my_network_leg = 11;
|
||||
string my_referral_code = 12;
|
||||
LastMemberModel last_member = 13;
|
||||
}
|
||||
|
||||
message LastMemberModel
|
||||
{
|
||||
int64 user_id = 1;
|
||||
string full_name = 2;
|
||||
string position = 3;
|
||||
int32 total_children = 4;
|
||||
}
|
||||
|
||||
// ============ GetMyNetworkPosition ============
|
||||
message GetMyNetworkPositionResponse
|
||||
{
|
||||
int64 user_id = 1;
|
||||
int64 parent_id = 2;
|
||||
string parent_name = 3;
|
||||
string position = 4; // Left/Right
|
||||
int32 level = 5;
|
||||
string referral_code = 6;
|
||||
google.protobuf.Timestamp joined_at = 7;
|
||||
bool has_left_child = 8;
|
||||
bool has_right_child = 9;
|
||||
}
|
||||
Reference in New Issue
Block a user