feat: Implement file management and authorization features
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 3m9s

- Add RequiresPermissionAttribute for gRPC method access control.
- Create IFileManagementService interface for file upload and management.
- Implement AddProductImageCommand and handler for adding product images.
- Implement CreateNewProductsCommand and handler for creating new products with image uploads.
- Implement DeleteProductsCommand and handler for deleting products and their associations.
- Implement RemoveProductImageCommand and handler for removing product images from galleries.
- Implement UpdateProductsCommand and handler for updating product details and images.
- Create GetProductGalleryQuery and handler for retrieving product galleries.
- Implement PermissionService for role-based access control using JWT claims.
- Implement FileManagementService for handling file uploads and image optimization.
- Define gRPC service and messages for file management in fms.proto.
- Add FluentValidation for request validation in various commands.
- Create PermissionInterceptor for enforcing permissions on gRPC methods.
This commit is contained in:
masoodafar-web
2026-02-10 22:04:54 +03:30
parent f64b6be7da
commit b42d9e141d
65 changed files with 3082 additions and 2384 deletions
@@ -87,6 +87,8 @@ message CreateDiscountProductRequest
int32 sort_order = 9;
bool is_active = 10;
repeated int64 category_ids = 11;
ImageFileModel image_file = 12;
ImageFileModel thumbnail_file = 13;
}
message CreateDiscountProductResponse
@@ -108,6 +110,8 @@ message UpdateDiscountProductRequest
int32 sort_order = 9;
bool is_active = 10;
repeated int64 category_ids = 11;
ImageFileModel image_file = 12;
ImageFileModel thumbnail_file = 13;
}
// Delete Product
@@ -246,3 +250,11 @@ message DiscountProductImageDto
int32 sort_order = 7;
bool is_active = 8;
}
// File upload model for binary image uploads from BackOffice
message ImageFileModel
{
bytes file = 1;
string mime = 2;
string file_name = 3;
}
@@ -0,0 +1,38 @@
syntax = "proto3";
package fms;
import "google/protobuf/wrappers.proto";
option csharp_namespace = "CMSMicroservice.Protobuf.Protos.FMS";
service FileInfoContract
{
rpc CreateNewFileInfo(CreateNewFileInfoRequest) returns (CreateNewFileInfoResponse);
rpc DeleteFileInfo(DeleteFileInfoRequest) returns (DeleteFileInfoResponse);
}
message CreateNewFileInfoRequest
{
string directory = 1;
bytes file = 2;
string mime = 3;
bool is_base64 = 4;
google.protobuf.StringValue file_name = 5;
}
message CreateNewFileInfoResponse
{
int64 id = 1;
string file = 2;
}
message DeleteFileInfoRequest
{
int64 id = 1;
}
message DeleteFileInfoResponse
{
bool success = 1;
}
@@ -270,6 +270,8 @@ message InventoryItemDto {
string product_title = 15;
int64 product_price = 16;
google.protobuf.Timestamp created = 17;
// آیا موجودی کم است (موجودی قابل فروش کمتر از حد هشدار)
bool is_low_stock = 18;
}
message GetInventoryItemRequest {
@@ -78,6 +78,7 @@ message CreateManualPaymentRequest
google.protobuf.StringValue reference_number = 5;
google.protobuf.StringValue image_path = 6;
google.protobuf.Int64Value image_document_id = 7;
FileUploadModel image_file = 8;
}
message CreateManualPaymentResponse
@@ -155,3 +156,11 @@ message ProcessManualMembershipPaymentResponse
string message = 4;
}
// File upload model for binary image uploads from BackOffice
message FileUploadModel
{
bytes file = 1;
string file_name = 2;
string mime = 3;
}
@@ -113,6 +113,7 @@ message CreateNewPackageRequest
string description = 2;
string image_path = 3;
int64 price = 4;
BoostCardFileModel image_file = 5;
}
message CreateNewPackageResponse
{
@@ -125,6 +126,7 @@ message UpdatePackageRequest
string description = 3;
string image_path = 4;
int64 price = 5;
BoostCardFileModel image_file = 6;
}
message DeletePackageRequest
{
@@ -412,3 +414,11 @@ enum PaymentStatusEnum
PAYMENT_STATUS_FAILED = 2;
PAYMENT_STATUS_REFUNDED = 3;
}
// File upload model for binary image uploads from BackOffice
message BoostCardFileModel
{
bytes file = 1;
string file_name = 2;
string mime = 3;
}
@@ -79,6 +79,50 @@ service ProductsContract
get: "/Customer/GetProducts"
};
};
// ============= Category-Product DragDrop Methods =============
rpc GetProductsForCategory(GetProductsForCategoryRequest) returns (GetProductsForCategoryResponse){
option (google.api.http) = {
get: "/GetProductsForCategory"
};
};
rpc GetCategories(GetCategoriesRequest) returns (GetCategoriesResponse){
option (google.api.http) = {
get: "/GetCategories"
};
};
rpc UpdateProductCategories(UpdateProductCategoriesRequest) returns (google.protobuf.Empty){
option (google.api.http) = {
post: "/UpdateProductCategories"
body: "*"
};
};
rpc UpdateCategoryProducts(UpdateCategoryProductsRequest) returns (google.protobuf.Empty){
option (google.api.http) = {
post: "/UpdateCategoryProducts"
body: "*"
};
};
// ============= Product Image Management =============
rpc AddProductImage(AddProductImageRequest) returns (AddProductImageResponse){
option (google.api.http) = {
post: "/AddProductImage"
body: "*"
};
};
rpc RemoveProductImage(RemoveProductImageRequest) returns (google.protobuf.Empty){
option (google.api.http) = {
delete: "/RemoveProductImage"
};
};
rpc GetProductGallery(GetProductGalleryRequest) returns (GetProductGalleryResponse){
option (google.api.http) = {
get: "/GetProductGallery"
};
};
}
message CreateNewProductsRequest
{
@@ -96,6 +140,10 @@ message CreateNewProductsRequest
int32 remaining_count = 12;
// لیست شناسه دسته‌بندی‌های محصول
repeated int64 category_ids = 13;
// فایل تصویر اصلی محصول (آپلود باینری)
ImageFileModel image_file = 14;
// فایل تصویر بندانگشتی محصول (آپلود باینری)
ImageFileModel thumbnail_file = 15;
}
message CreateNewProductsResponse
{
@@ -118,6 +166,10 @@ message UpdateProductsRequest
int32 remaining_count = 13;
// لیست شناسه دسته‌بندی‌های محصول
repeated int64 category_ids = 14;
// فایل تصویر اصلی محصول (آپلود باینری)
ImageFileModel image_file = 15;
// فایل تصویر بندانگشتی محصول (آپلود باینری)
ImageFileModel thumbnail_file = 16;
}
message DeleteProductsRequest
{
@@ -334,3 +386,97 @@ message ToggleProductStatusResponse
int32 failed = 3;
repeated BulkOperationError errors = 4;
}
// Category Product Item (for drag-drop UI)
message CategoryProductItem
{
int64 id = 1;
string title = 2;
bool selected = 3;
}
// Get Products for Category
message GetProductsForCategoryRequest
{
int64 category_id = 1;
}
message GetProductsForCategoryResponse
{
repeated CategoryProductItem items = 1;
}
// Category Item (for product categories drag-drop)
message CategoryItem
{
int64 id = 1;
string title = 2;
bool selected = 3;
}
// Get Categories for Product
message GetCategoriesRequest
{
int64 product_id = 1;
}
message GetCategoriesResponse
{
repeated CategoryItem items = 1;
}
// Update Product Categories
message UpdateProductCategoriesRequest
{
int64 product_id = 1;
repeated int64 category_ids = 2;
}
// Update Category Products
message UpdateCategoryProductsRequest
{
int64 category_id = 1;
repeated int64 product_ids = 2;
}
// Image File Model
message ImageFileModel
{
bytes file = 1;
string mime = 2;
string file_name = 3;
}
// Get Product Gallery
message GetProductGalleryRequest
{
int64 product_id = 1;
}
message GetProductGalleryResponse
{
repeated ProductGalleryItem items = 1;
}
// Add Product Image
message AddProductImageRequest
{
int64 product_id = 1;
string title = 2;
ImageFileModel image_file = 3;
}
message AddProductImageResponse
{
int64 product_gallery_id = 1;
int64 product_image_id = 2;
string title = 3;
string image_path = 4;
string image_thumbnail_path = 5;
}
// Remove Product Image
message RemoveProductImageRequest
{
int64 product_gallery_id = 1;
}