Add MediatR commands/queries/handlers and DTOs
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
using MediatR;
|
||||
using Printbase.Application.Products.Dtos;
|
||||
|
||||
namespace Printbase.Application.Products.Commands;
|
||||
|
||||
public class CreateCategoryCommand : IRequest<CategoryDto>
|
||||
{
|
||||
public string Name { get; set; } = null!;
|
||||
public string Description { get; set; } = null!;
|
||||
public string? ImageUrl { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
public Guid? ParentCategoryId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using MediatR;
|
||||
using Printbase.Application.Products.Dtos;
|
||||
|
||||
namespace Printbase.Application.Products.Commands;
|
||||
|
||||
public class CreateProductCommand : IRequest<ProductDto>
|
||||
{
|
||||
public string Name { get; set; } = null!;
|
||||
public string? Description { get; set; }
|
||||
public decimal BasePrice { get; set; }
|
||||
public bool IsCustomizable { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
public string? ImageUrl { get; set; }
|
||||
public Guid? CategoryId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using MediatR;
|
||||
using Printbase.Application.Products.Dtos;
|
||||
|
||||
namespace Printbase.Application.Products.Commands;
|
||||
|
||||
public class CreateProductVariantCommand : IRequest<ProductVariantDto>
|
||||
{
|
||||
public Guid ProductId { get; set; }
|
||||
public string Size { get; set; } = null!;
|
||||
public string? Color { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public string? ImageUrl { get; set; }
|
||||
public string Sku { get; set; } = null!;
|
||||
public int StockQuantity { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using MediatR;
|
||||
|
||||
namespace Printbase.Application.Products.Commands;
|
||||
|
||||
public class DeleteCategoryCommand : IRequest<bool>
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using MediatR;
|
||||
|
||||
namespace Printbase.Application.Products.Commands;
|
||||
|
||||
public class DeleteProductCommand : IRequest<bool>
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using MediatR;
|
||||
|
||||
namespace Printbase.Application.Products.Commands;
|
||||
|
||||
public class DeleteProductVariantCommand : IRequest<bool>
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
14
src/Printbase.Application/Products/Dtos/CategoryDto.cs
Normal file
14
src/Printbase.Application/Products/Dtos/CategoryDto.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Printbase.Application.Products.Dtos;
|
||||
|
||||
public class CategoryDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string Name { get; set; } = null!;
|
||||
public string Description { get; set; } = null!;
|
||||
public string? ImageUrl { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public Guid? ParentCategoryId { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime ModifiedAt { get; set; }
|
||||
}
|
||||
12
src/Printbase.Application/Products/Dtos/PagedResultDto.cs
Normal file
12
src/Printbase.Application/Products/Dtos/PagedResultDto.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Printbase.Application.Products.Dtos;
|
||||
|
||||
public class PagedResultDto<T>
|
||||
{
|
||||
public IEnumerable<T> Items { get; set; } = new List<T>();
|
||||
public int TotalCount { get; set; }
|
||||
public int PageNumber { get; set; }
|
||||
public int PageSize { get; set; }
|
||||
public int TotalPages => (int)Math.Ceiling((double)TotalCount / PageSize);
|
||||
public bool HasPreviousPage => PageNumber > 1;
|
||||
public bool HasNextPage => PageNumber < TotalPages;
|
||||
}
|
||||
16
src/Printbase.Application/Products/Dtos/ProductDto.cs
Normal file
16
src/Printbase.Application/Products/Dtos/ProductDto.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace Printbase.Application.Products.Dtos;
|
||||
|
||||
public class ProductDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string Name { get; set; } = null!;
|
||||
public string? Description { get; set; }
|
||||
public decimal BasePrice { get; set; }
|
||||
public bool IsCustomizable { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public string? ImageUrl { get; set; }
|
||||
public Guid? CategoryId { get; set; }
|
||||
public CategoryDto? Category { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime ModifiedAt { get; set; }
|
||||
}
|
||||
17
src/Printbase.Application/Products/Dtos/ProductVariantDto.cs
Normal file
17
src/Printbase.Application/Products/Dtos/ProductVariantDto.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace Printbase.Application.Products.Dtos;
|
||||
|
||||
public class ProductVariantDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid ProductId { get; set; }
|
||||
public string Size { get; set; } = null!;
|
||||
public string? Color { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public string? ImageUrl { get; set; }
|
||||
public string Sku { get; set; } = null!;
|
||||
public int StockQuantity { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public ProductDto? Product { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime ModifiedAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using MediatR;
|
||||
using Printbase.Application.Products.Commands;
|
||||
using Printbase.Application.Products.Dtos;
|
||||
using Printbase.Domain.Entities.Product;
|
||||
|
||||
namespace Printbase.Application.Products.Handlers;
|
||||
|
||||
public class CreateCategoryHandler(IUnitOfWork unitOfWork) : IRequestHandler<CreateCategoryCommand, CategoryDto>
|
||||
{
|
||||
public async Task<CategoryDto> Handle(CreateCategoryCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await unitOfWork.BeginTransactionAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var category = new Category
|
||||
{
|
||||
Name = request.Name,
|
||||
Description = request.Description,
|
||||
ImageUrl = request.ImageUrl,
|
||||
SortOrder = request.SortOrder,
|
||||
IsActive = request.IsActive,
|
||||
ParentCategoryId = request.ParentCategoryId
|
||||
};
|
||||
|
||||
var createdCategory = await unitOfWork.CategoryRepository.AddAsync(category, cancellationToken);
|
||||
await unitOfWork.CommitTransactionAsync();
|
||||
|
||||
return new CategoryDto
|
||||
{
|
||||
Id = createdCategory.Id,
|
||||
Name = createdCategory.Name,
|
||||
Description = createdCategory.Description,
|
||||
ImageUrl = createdCategory.ImageUrl,
|
||||
SortOrder = createdCategory.SortOrder,
|
||||
IsActive = createdCategory.IsActive,
|
||||
ParentCategoryId = createdCategory.ParentCategoryId,
|
||||
CreatedAt = createdCategory.CreatedAt,
|
||||
ModifiedAt = createdCategory.ModifiedAt
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using MediatR;
|
||||
using Printbase.Application.Products.Commands;
|
||||
using Printbase.Application.Products.Dtos;
|
||||
using Printbase.Domain.Entities.Product;
|
||||
|
||||
namespace Printbase.Application.Products.Handlers;
|
||||
|
||||
public class CreateProductHandler(IUnitOfWork unitOfWork) : IRequestHandler<CreateProductCommand, ProductDto>
|
||||
{
|
||||
public async Task<ProductDto> Handle(CreateProductCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await unitOfWork.BeginTransactionAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var product = new Product
|
||||
{
|
||||
Name = request.Name,
|
||||
Description = request.Description,
|
||||
BasePrice = request.BasePrice,
|
||||
IsCustomizable = request.IsCustomizable,
|
||||
IsActive = request.IsActive,
|
||||
ImageUrl = request.ImageUrl,
|
||||
CategoryId = request.CategoryId,
|
||||
Category = null!
|
||||
};
|
||||
|
||||
var createdProduct = await unitOfWork.ProductRepository.AddAsync(product, cancellationToken);
|
||||
await unitOfWork.CommitTransactionAsync();
|
||||
|
||||
var categoryDto = new CategoryDto
|
||||
{
|
||||
Id = createdProduct.Category.Id,
|
||||
Name = createdProduct.Category.Name,
|
||||
Description = createdProduct.Category.Description,
|
||||
ImageUrl = createdProduct.Category.ImageUrl,
|
||||
SortOrder = createdProduct.Category.SortOrder,
|
||||
IsActive = createdProduct.Category.IsActive,
|
||||
ParentCategoryId = createdProduct.Category.ParentCategoryId,
|
||||
CreatedAt = createdProduct.Category.CreatedAt,
|
||||
ModifiedAt = createdProduct.Category.ModifiedAt
|
||||
};
|
||||
|
||||
return new ProductDto
|
||||
{
|
||||
Id = createdProduct.Id,
|
||||
Name = createdProduct.Name,
|
||||
Description = createdProduct.Description,
|
||||
BasePrice = createdProduct.BasePrice,
|
||||
IsCustomizable = createdProduct.IsCustomizable,
|
||||
IsActive = createdProduct.IsActive,
|
||||
ImageUrl = createdProduct.ImageUrl,
|
||||
CategoryId = createdProduct.CategoryId,
|
||||
Category = categoryDto,
|
||||
CreatedAt = createdProduct.CreatedAt,
|
||||
ModifiedAt = createdProduct.ModifiedAt
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using MediatR;
|
||||
using Printbase.Application.Products.Commands;
|
||||
using Printbase.Application.Products.Dtos;
|
||||
using Printbase.Domain.Entities.Product;
|
||||
|
||||
namespace Printbase.Application.Products.Handlers;
|
||||
|
||||
public class CreateProductVariantHandler(IUnitOfWork unitOfWork)
|
||||
: IRequestHandler<CreateProductVariantCommand, ProductVariantDto>
|
||||
{
|
||||
public async Task<ProductVariantDto> Handle(CreateProductVariantCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await unitOfWork.BeginTransactionAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var productVariant = new ProductVariant
|
||||
{
|
||||
ProductId = request.ProductId,
|
||||
Size = request.Size,
|
||||
Color = request.Color,
|
||||
Price = request.Price,
|
||||
ImageUrl = request.ImageUrl,
|
||||
Sku = request.Sku,
|
||||
StockQuantity = request.StockQuantity,
|
||||
IsActive = request.IsActive,
|
||||
Product = null!
|
||||
};
|
||||
|
||||
var createdVariant = await unitOfWork.ProductVariantRepository.AddAsync(productVariant, cancellationToken);
|
||||
await unitOfWork.CommitTransactionAsync();
|
||||
|
||||
return new ProductVariantDto
|
||||
{
|
||||
Id = createdVariant.Id,
|
||||
ProductId = createdVariant.ProductId,
|
||||
Size = createdVariant.Size,
|
||||
Color = createdVariant.Color,
|
||||
Price = createdVariant.Price,
|
||||
ImageUrl = createdVariant.ImageUrl,
|
||||
Sku = createdVariant.Sku,
|
||||
StockQuantity = createdVariant.StockQuantity,
|
||||
IsActive = createdVariant.IsActive,
|
||||
CreatedAt = createdVariant.CreatedAt,
|
||||
ModifiedAt = createdVariant.ModifiedAt
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using MediatR;
|
||||
using Printbase.Application.Products.Commands;
|
||||
|
||||
namespace Printbase.Application.Products.Handlers;
|
||||
|
||||
public class DeleteCategoryHandler(IUnitOfWork unitOfWork) : IRequestHandler<DeleteCategoryCommand, bool>
|
||||
{
|
||||
public async Task<bool> Handle(DeleteCategoryCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await unitOfWork.BeginTransactionAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var exists = await unitOfWork.CategoryRepository.ExistsAsync(request.Id, cancellationToken);
|
||||
if (!exists)
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync();
|
||||
return false;
|
||||
}
|
||||
|
||||
await unitOfWork.CategoryRepository.DeleteAsync(request.Id, cancellationToken);
|
||||
await unitOfWork.CommitTransactionAsync();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using MediatR;
|
||||
using Printbase.Application.Products.Commands;
|
||||
|
||||
namespace Printbase.Application.Products.Handlers;
|
||||
|
||||
public class DeleteProductHandler(IUnitOfWork unitOfWork) : IRequestHandler<DeleteProductCommand, bool>
|
||||
{
|
||||
public async Task<bool> Handle(DeleteProductCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await unitOfWork.BeginTransactionAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var exists = await unitOfWork.ProductRepository.ExistsAsync(request.Id, cancellationToken);
|
||||
if (!exists)
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync();
|
||||
return false;
|
||||
}
|
||||
|
||||
await unitOfWork.ProductRepository.DeleteAsync(request.Id, cancellationToken);
|
||||
await unitOfWork.CommitTransactionAsync();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using MediatR;
|
||||
using Printbase.Application.Products.Commands;
|
||||
|
||||
namespace Printbase.Application.Products.Handlers;
|
||||
|
||||
public class DeleteProductVariantHandler(IUnitOfWork unitOfWork) : IRequestHandler<DeleteProductVariantCommand, bool>
|
||||
{
|
||||
public async Task<bool> Handle(DeleteProductVariantCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await unitOfWork.BeginTransactionAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var exists = await unitOfWork.ProductVariantRepository.ExistsAsync(request.Id, cancellationToken);
|
||||
if (!exists)
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync();
|
||||
return false;
|
||||
}
|
||||
|
||||
await unitOfWork.ProductVariantRepository.DeleteAsync(request.Id, cancellationToken);
|
||||
await unitOfWork.CommitTransactionAsync();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using MediatR;
|
||||
using Printbase.Application.Products.Dtos;
|
||||
using Printbase.Application.Products.Queries;
|
||||
|
||||
namespace Printbase.Application.Products.Handlers;
|
||||
|
||||
public class GetProductsHandler(IUnitOfWork unitOfWork) : IRequestHandler<GetProductsQuery, PagedResultDto<ProductDto>>
|
||||
{
|
||||
public async Task<PagedResultDto<ProductDto>> Handle(GetProductsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var pagedResult = await unitOfWork.ProductRepository.GetPagedAsync(request.FilterParameters, cancellationToken);
|
||||
|
||||
var productDtos = pagedResult.Items.Select(p => new ProductDto
|
||||
{
|
||||
Id = p.Id,
|
||||
Name = p.Name,
|
||||
Description = p.Description,
|
||||
BasePrice = p.BasePrice,
|
||||
IsCustomizable = p.IsCustomizable,
|
||||
IsActive = p.IsActive,
|
||||
ImageUrl = p.ImageUrl,
|
||||
CategoryId = p.CategoryId,
|
||||
Category = new CategoryDto
|
||||
{
|
||||
Id = p.Category.Id,
|
||||
Name = p.Category.Name,
|
||||
Description = p.Category.Description,
|
||||
ImageUrl = p.Category.ImageUrl,
|
||||
SortOrder = p.Category.SortOrder,
|
||||
IsActive = p.Category.IsActive,
|
||||
ParentCategoryId = p.Category.ParentCategoryId,
|
||||
CreatedAt = p.Category.CreatedAt,
|
||||
ModifiedAt = p.Category.ModifiedAt
|
||||
},
|
||||
CreatedAt = p.CreatedAt,
|
||||
ModifiedAt = p.ModifiedAt
|
||||
});
|
||||
|
||||
return new PagedResultDto<ProductDto>
|
||||
{
|
||||
Items = productDtos,
|
||||
TotalCount = pagedResult.TotalCount,
|
||||
PageNumber = pagedResult.PageNumber,
|
||||
PageSize = pagedResult.PageSize
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using MediatR;
|
||||
using Printbase.Application.Products.Dtos;
|
||||
using Printbase.Domain.Common.Models;
|
||||
|
||||
namespace Printbase.Application.Products.Queries;
|
||||
|
||||
public class GetProductsQuery : IRequest<PagedResultDto<ProductDto>>
|
||||
{
|
||||
public ProductFilterParameters FilterParameters { get; set; } = new();
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MediatR" Version="12.5.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Printbase.Application.Products.Handlers;
|
||||
using Printbase.Domain.Entities.Users;
|
||||
using Printbase.Infrastructure.Database;
|
||||
|
||||
@@ -16,6 +17,11 @@ public static class Startup
|
||||
builder.Configuration.GetConnectionString("DefaultConnection"),
|
||||
b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));
|
||||
|
||||
services.AddMediatR(cfg =>
|
||||
{
|
||||
cfg.RegisterServicesFromAssembly(typeof(CreateProductHandler).Assembly);
|
||||
});
|
||||
|
||||
services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
|
||||
{
|
||||
options.Password.RequireDigit = true;
|
||||
|
||||
Reference in New Issue
Block a user