-
-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e8daf0d
commit 6da7c27
Showing
27 changed files
with
674 additions
and
30 deletions.
There are no files selected for viewing
20 changes: 20 additions & 0 deletions
20
src/Application/Common/DTOs/Product/ProductForUpdateDto.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using System.Collections.ObjectModel; | ||
|
||
namespace Application.Common.DTOs.Product; | ||
|
||
public class ProductForUpdateDto | ||
{ | ||
public string Id { get; set; } | ||
|
||
public string Name { get; set; } | ||
|
||
public string Description { get; set; } | ||
|
||
public int Price { get; set; } | ||
|
||
public long BookStorageLimit { get; set; } | ||
|
||
public int AiRequestLimit { get; set; } | ||
|
||
public ICollection<string> Features { get; set; } = new Collection<string>(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System.Collections.ObjectModel; | ||
using System.ComponentModel.DataAnnotations; | ||
|
||
namespace Application.Common.DTOs.Product; | ||
|
||
public class ProductInDto | ||
{ | ||
[Required] | ||
public string Id { get; set; } | ||
|
||
[Required] | ||
public string Name { get; set; } | ||
|
||
[Required] | ||
public string Description { get; set; } | ||
|
||
[Required] | ||
public long BookStorageLimit { get; set; } | ||
|
||
[Required] | ||
public int AiRequestLimit { get; set; } | ||
|
||
[Required] | ||
public ICollection<string> Features { get; set; } = new Collection<string>(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System.Collections.ObjectModel; | ||
|
||
namespace Application.Common.DTOs.Product; | ||
|
||
public class ProductOutDto | ||
{ | ||
public string Id { get; set; } | ||
|
||
public bool Active { get; set; } | ||
|
||
public string Name { get; set; } | ||
|
||
public string Description { get; set; } | ||
|
||
public int Price { get; set; } | ||
|
||
public ICollection<string> Features { get; set; } = new Collection<string>(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
src/Application/Common/Mappings/ProductAutoMapperProfile.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using Application.Common.DTOs.Highlights; | ||
using Application.Common.DTOs.Product; | ||
using AutoMapper; | ||
using Domain.Entities; | ||
|
||
namespace Application.Common.Mappings; | ||
|
||
public class ProductAutoMapperProfile : Profile | ||
{ | ||
public ProductAutoMapperProfile() | ||
{ | ||
CreateMap<ProductInDto, Product>() | ||
.ForMember(dest => dest.ProductId, temp => temp.MapFrom(src => src.Id)) | ||
.ForMember(dest => dest.Features, temp => temp.Ignore()) | ||
.ForMember(dest => dest.Price, temp => temp.Ignore()); | ||
CreateMap<Product, ProductOutDto>() | ||
.ForMember(dest => dest.Id, temp => temp.MapFrom(src => src.ProductId.ToString())) | ||
.ForMember(dest => dest.Features, temp => temp.MapFrom(src => src.Features.Select(feature => feature.Name))); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
src/Application/Interfaces/Repositories/IProductRepository.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using Domain.Entities; | ||
|
||
namespace Application.Interfaces.Repositories; | ||
|
||
public interface IProductRepository | ||
{ | ||
public Task<int> SaveChangesAsync(); | ||
public void CreateProduct(Product product); | ||
public IQueryable<Product> GetAll(); | ||
public Task<Product> GetByIdAsync(string id); | ||
public void DeleteProduct(Product product); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using Application.Common.DTOs.Product; | ||
|
||
namespace Application.Interfaces.Services; | ||
|
||
public interface IProductService | ||
{ | ||
public Task<IEnumerable<ProductOutDto>> GetAllProductsAsync(); | ||
public Task CreateProductAsync(ProductInDto productInDto); | ||
public Task UpdateProductAsync(ProductForUpdateDto productInDto); | ||
public Task DeleteProductAsync(string id); | ||
public Task AddPriceToProductAsync(string id, int price); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
using Application.Common.DTOs.Product; | ||
using Application.Common.Exceptions; | ||
using Application.Interfaces.Repositories; | ||
using Application.Interfaces.Services; | ||
using AutoMapper; | ||
using Domain.Entities; | ||
using Microsoft.EntityFrameworkCore; | ||
|
||
namespace Application.Services; | ||
|
||
public class ProductService(IMapper mapper, IProductRepository productRepository) : IProductService | ||
{ | ||
private IMapper Mapper { get; } = mapper; | ||
private IProductRepository ProductRepository { get; } = productRepository; | ||
Check warning on line 14 in src/Application/Services/ProductService.cs GitHub Actions / test
Check warning on line 14 in src/Application/Services/ProductService.cs GitHub Actions / deploy
|
||
|
||
public async Task<IEnumerable<ProductOutDto>> GetAllProductsAsync() | ||
{ | ||
var products = await productRepository.GetAll().ToListAsync(); | ||
return products.Select(product => Mapper.Map<ProductOutDto>(product)); | ||
} | ||
|
||
public async Task CreateProductAsync(ProductInDto productInDto) | ||
{ | ||
var product = Mapper.Map<Product>(productInDto); | ||
foreach(var feature in productInDto.Features) | ||
{ | ||
product.Features.Add(new ProductFeature | ||
{ | ||
Name = feature | ||
}); | ||
} | ||
productRepository.CreateProduct(product); | ||
|
||
await productRepository.SaveChangesAsync(); | ||
} | ||
|
||
public async Task UpdateProductAsync(ProductForUpdateDto productUpdateDto) | ||
{ | ||
var product = await productRepository.GetByIdAsync(productUpdateDto.Id); | ||
|
||
// The update gets sent at the same time as the product is created, we need to wait for the product to be created | ||
int tries = 0; | ||
while(product == null && tries < 3) | ||
{ | ||
await Task.Delay(200); | ||
product = await productRepository.GetByIdAsync(productUpdateDto.Id); | ||
tries++; | ||
} | ||
|
||
if (product == null) | ||
{ | ||
const string message = "No product with this id exists"; | ||
throw new CommonErrorException(404, message, 0); | ||
} | ||
|
||
bool hasChanged = false; | ||
var dtoProperties = productUpdateDto.GetType().GetProperties(); | ||
foreach (var dtoProperty in dtoProperties) | ||
{ | ||
// Manually handle certain properties | ||
switch (dtoProperty.Name) | ||
{ | ||
case "Id": | ||
continue; // Can't modify the GUID | ||
case "Features": | ||
{ | ||
// Remove all existing features | ||
product.Features.Clear(); | ||
|
||
// Add all new features | ||
foreach (var feature in productUpdateDto.Features) | ||
{ | ||
product.Features.Add(new ProductFeature | ||
{ | ||
Name = feature | ||
}); | ||
} | ||
|
||
hasChanged = true; | ||
continue; | ||
} | ||
} | ||
|
||
var productProperty = product.GetType().GetProperty(dtoProperty.Name); | ||
var productValue = productProperty.GetValue(product); | ||
var dtoValue = dtoProperty.GetValue(productUpdateDto); | ||
if (productValue == dtoValue) | ||
continue; | ||
|
||
// Handle this after the check if the values are the same | ||
if (dtoProperty.Name == "Price") | ||
{ | ||
if (productUpdateDto.Price == 0) | ||
continue; | ||
|
||
product.Price = productUpdateDto.Price; | ||
} | ||
|
||
// Update any other property via reflection | ||
var value = dtoProperty.GetValue(productUpdateDto); | ||
SetPropertyOnProduct(product, dtoProperty.Name, value); | ||
hasChanged = true; | ||
} | ||
|
||
if(hasChanged) | ||
await ProductRepository.SaveChangesAsync(); | ||
} | ||
|
||
private void SetPropertyOnProduct(Product product, string property, object value) | ||
{ | ||
var bookProperty = product.GetType().GetProperty(property); | ||
if (bookProperty == null) | ||
{ | ||
var message = "Product has no property called: " + property; | ||
throw new CommonErrorException(400, message, 0); | ||
} | ||
|
||
bookProperty.SetValue(product, value); | ||
} | ||
|
||
public async Task DeleteProductAsync(string id) | ||
{ | ||
var product = await productRepository.GetByIdAsync(id); | ||
if (product == null) | ||
{ | ||
const string message = "No product with this id exists"; | ||
throw new CommonErrorException(404, message, 0); | ||
} | ||
|
||
productRepository.DeleteProduct(product); | ||
await productRepository.SaveChangesAsync(); | ||
} | ||
|
||
public async Task AddPriceToProductAsync(string id, int price) | ||
{ | ||
var product = await productRepository.GetByIdAsync(id); | ||
|
||
// The price gets sent at the same time as the product is created, we need to wait for the product to be created | ||
int tries = 0; | ||
while(product == null && tries < 3) | ||
{ | ||
await Task.Delay(300); | ||
product = await productRepository.GetByIdAsync(id); | ||
tries++; | ||
} | ||
|
||
if (product == null) | ||
{ | ||
const string message = "No product with this id exists"; | ||
throw new CommonErrorException(404, message, 0); | ||
} | ||
|
||
product.Price = price; | ||
await productRepository.SaveChangesAsync(); | ||
} | ||
} |
Oops, something went wrong.