feat: Implement file management and authorization features
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 3m9s
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:
@@ -16,7 +16,10 @@ using CMSMicroservice.Application.UserCQ.Commands.AcceptContract;
|
||||
using CMSMicroservice.Application.UserCQ.Queries.GetCustomerProfile;
|
||||
using CMSMicroservice.Application.UserCQ.Queries.GetCustomerReferrals;
|
||||
using CMSMicroservice.Application.UserCQ.Queries.GetCustomerSettings;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Grpc.Core;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediatR;
|
||||
@@ -28,11 +31,25 @@ public class UserService : UserContract.UserContractBase
|
||||
{
|
||||
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
||||
private readonly ISender _sender;
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
private readonly IHashService _hashService;
|
||||
private readonly IFileManagementService _fileManagementService;
|
||||
|
||||
public UserService(IDispatchRequestToCQRS dispatchRequestToCQRS, ISender sender)
|
||||
public UserService(
|
||||
IDispatchRequestToCQRS dispatchRequestToCQRS,
|
||||
ISender sender,
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUserService,
|
||||
IHashService hashService,
|
||||
IFileManagementService fileManagementService)
|
||||
{
|
||||
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||
_sender = sender;
|
||||
_context = context;
|
||||
_currentUserService = currentUserService;
|
||||
_hashService = hashService;
|
||||
_fileManagementService = fileManagementService;
|
||||
}
|
||||
public override async Task<CreateNewUserResponse> CreateNewUser(CreateNewUserRequest request, ServerCallContext context)
|
||||
{
|
||||
@@ -90,33 +107,58 @@ public class UserService : UserContract.UserContractBase
|
||||
|
||||
public override async Task<GetUserForCustomerResponse> GetUserForCustomer(GetUserForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock implementation for Customer Get User
|
||||
await Task.Delay(10); // Simulate async operation
|
||||
var userId = GetCurrentUserId();
|
||||
|
||||
var user = await _context.Users
|
||||
.AsNoTracking()
|
||||
.Where(u => u.Id == userId && !u.IsDeleted)
|
||||
.FirstOrDefaultAsync(context.CancellationToken);
|
||||
|
||||
if (user == null)
|
||||
throw new RpcException(new Status(StatusCode.NotFound, "کاربر یافت نشد"));
|
||||
|
||||
return new GetUserForCustomerResponse
|
||||
{
|
||||
Id = 123,
|
||||
FirstName = "احمد",
|
||||
LastName = "محمدی",
|
||||
Mobile = "09123456789",
|
||||
Email = "ahmad.mohammadi@example.com",
|
||||
NationalCode = "1234567890",
|
||||
AvatarPath = "/avatars/user_123.jpg",
|
||||
ParentId = 100,
|
||||
ReferralCode = "REF123456",
|
||||
IsMobileVerified = true,
|
||||
MobileVerifiedAt = Timestamp.FromDateTime(DateTime.SpecifyKind(new DateTime(2024, 1, 15), DateTimeKind.Utc)),
|
||||
EmailNotifications = true,
|
||||
SmsNotifications = true,
|
||||
PushNotifications = false,
|
||||
BirthDate = Timestamp.FromDateTime(DateTime.SpecifyKind(new DateTime(1990, 5, 20), DateTimeKind.Utc))
|
||||
Id = user.Id,
|
||||
FirstName = user.FirstName ?? string.Empty,
|
||||
LastName = user.LastName ?? string.Empty,
|
||||
Mobile = user.Mobile,
|
||||
Email = user.Email ?? string.Empty,
|
||||
NationalCode = user.NationalCode ?? string.Empty,
|
||||
AvatarPath = user.AvatarPath ?? string.Empty,
|
||||
ParentId = user.NetworkParentId,
|
||||
ReferralCode = user.ReferralCode ?? string.Empty,
|
||||
IsMobileVerified = user.IsMobileVerified,
|
||||
MobileVerifiedAt = user.MobileVerifiedAt.HasValue
|
||||
? Timestamp.FromDateTime(DateTime.SpecifyKind(user.MobileVerifiedAt.Value, DateTimeKind.Utc))
|
||||
: null,
|
||||
EmailNotifications = user.EmailNotifications,
|
||||
SmsNotifications = user.SmsNotifications,
|
||||
PushNotifications = user.PushNotifications,
|
||||
BirthDate = user.BirthDate.HasValue
|
||||
? Timestamp.FromDateTime(DateTime.SpecifyKind(user.BirthDate.Value, DateTimeKind.Utc))
|
||||
: null
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<Empty> UpdateCustomerProfile(UpdateCustomerProfileRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock implementation for Update Customer Profile
|
||||
await Task.Delay(10);
|
||||
var userId = GetCurrentUserId();
|
||||
|
||||
var user = await _context.Users
|
||||
.Where(u => u.Id == userId && !u.IsDeleted)
|
||||
.FirstOrDefaultAsync(context.CancellationToken);
|
||||
|
||||
if (user == null)
|
||||
throw new RpcException(new Status(StatusCode.NotFound, "کاربر یافت نشد"));
|
||||
|
||||
if (request.FirstName != null) user.FirstName = request.FirstName;
|
||||
if (request.LastName != null) user.LastName = request.LastName;
|
||||
if (request.Email != null) user.Email = request.Email;
|
||||
if (request.NationalCode != null) user.NationalCode = request.NationalCode;
|
||||
if (request.BirthDate != null) user.BirthDate = request.BirthDate.ToDateTime();
|
||||
|
||||
await _context.SaveChangesAsync(context.CancellationToken);
|
||||
return new Empty();
|
||||
}
|
||||
|
||||
@@ -153,9 +195,6 @@ public class UserService : UserContract.UserContractBase
|
||||
|
||||
public override async Task<ChangeCustomerPasswordResponse> ChangeCustomerPassword(ChangeCustomerPasswordRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock implementation for Change Customer Password
|
||||
await Task.Delay(10);
|
||||
|
||||
if (request.NewPassword != request.ConfirmPassword)
|
||||
{
|
||||
return new ChangeCustomerPasswordResponse
|
||||
@@ -174,6 +213,32 @@ public class UserService : UserContract.UserContractBase
|
||||
};
|
||||
}
|
||||
|
||||
var userId = GetCurrentUserId();
|
||||
|
||||
var user = await _context.Users
|
||||
.Where(u => u.Id == userId && !u.IsDeleted)
|
||||
.FirstOrDefaultAsync(context.CancellationToken);
|
||||
|
||||
if (user == null)
|
||||
throw new RpcException(new Status(StatusCode.NotFound, "کاربر یافت نشد"));
|
||||
|
||||
// Verify current password
|
||||
if (!string.IsNullOrEmpty(user.HashPassword))
|
||||
{
|
||||
if (!_hashService.VerifyPassword(request.CurrentPassword, user.HashPassword))
|
||||
{
|
||||
return new ChangeCustomerPasswordResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = "رمز عبور فعلی نادرست است"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Hash and save new password
|
||||
user.HashPassword = _hashService.HashPassword(request.NewPassword);
|
||||
await _context.SaveChangesAsync(context.CancellationToken);
|
||||
|
||||
return new ChangeCustomerPasswordResponse
|
||||
{
|
||||
Success = true,
|
||||
@@ -233,9 +298,6 @@ public class UserService : UserContract.UserContractBase
|
||||
|
||||
public override async Task<UploadCustomerAvatarResponse> UploadCustomerAvatar(UploadCustomerAvatarRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock implementation for Upload Customer Avatar
|
||||
await Task.Delay(10);
|
||||
|
||||
if (request.FileData == null || request.FileData.Length == 0)
|
||||
{
|
||||
return new UploadCustomerAvatarResponse
|
||||
@@ -264,10 +326,36 @@ public class UserService : UserContract.UserContractBase
|
||||
};
|
||||
}
|
||||
|
||||
// Simulate file upload and generate URL
|
||||
var fileName = $"avatar_{DateTime.Now.Ticks}.{request.FileMimeType?.Split('/').LastOrDefault()}";
|
||||
var avatarUrl = $"/uploads/avatars/{fileName}";
|
||||
|
||||
var userId = GetCurrentUserId();
|
||||
|
||||
var user = await _context.Users
|
||||
.Where(u => u.Id == userId && !u.IsDeleted)
|
||||
.FirstOrDefaultAsync(context.CancellationToken);
|
||||
|
||||
if (user == null)
|
||||
throw new RpcException(new Status(StatusCode.NotFound, "کاربر یافت نشد"));
|
||||
|
||||
// Upload to FMS
|
||||
var fileBytes = request.FileData.ToByteArray();
|
||||
var fileName = $"avatar_{userId}_{DateTime.UtcNow.Ticks}";
|
||||
var mime = request.FileMimeType ?? "image/jpeg";
|
||||
|
||||
var avatarUrl = await _fileManagementService.UploadFileAsync(
|
||||
"Avatars", fileBytes, mime, fileName, context.CancellationToken);
|
||||
|
||||
if (string.IsNullOrEmpty(avatarUrl))
|
||||
{
|
||||
return new UploadCustomerAvatarResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = "خطا در آپلود فایل. لطفاً مجدد تلاش کنید"
|
||||
};
|
||||
}
|
||||
|
||||
// Update user avatar path in DB
|
||||
user.AvatarPath = avatarUrl;
|
||||
await _context.SaveChangesAsync(context.CancellationToken);
|
||||
|
||||
return new UploadCustomerAvatarResponse
|
||||
{
|
||||
Success = true,
|
||||
@@ -295,8 +383,32 @@ public class UserService : UserContract.UserContractBase
|
||||
|
||||
public override async Task<Empty> UpdateCustomerSettings(UpdateCustomerSettingsRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock implementation for Update Customer Settings
|
||||
await Task.Delay(10);
|
||||
var userId = GetCurrentUserId();
|
||||
|
||||
var user = await _context.Users
|
||||
.Where(u => u.Id == userId && !u.IsDeleted)
|
||||
.FirstOrDefaultAsync(context.CancellationToken);
|
||||
|
||||
if (user == null)
|
||||
throw new RpcException(new Status(StatusCode.NotFound, "کاربر یافت نشد"));
|
||||
|
||||
user.EmailNotifications = request.EmailNotifications;
|
||||
user.SmsNotifications = request.SmsNotifications;
|
||||
user.PushNotifications = request.PushNotifications;
|
||||
// MarketingNotifications, PreferredLanguage, TimeZone, TwoFactorAuth
|
||||
// are stored at application level if needed in future
|
||||
|
||||
await _context.SaveChangesAsync(context.CancellationToken);
|
||||
return new Empty();
|
||||
}
|
||||
|
||||
// ============= Helper Methods =============
|
||||
|
||||
private long GetCurrentUserId()
|
||||
{
|
||||
if (long.TryParse(_currentUserService.UserId, out var userId) && userId > 0)
|
||||
return userId;
|
||||
|
||||
throw new RpcException(new Status(StatusCode.Unauthenticated, "لطفاً وارد حساب کاربری خود شوید"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user