diff --git a/Webshop.Api/Controllers/Public/ProductsController.cs b/Webshop.Api/Controllers/Public/ProductsController.cs
index 77316a9..a546f5b 100644
--- a/Webshop.Api/Controllers/Public/ProductsController.cs
+++ b/Webshop.Api/Controllers/Public/ProductsController.cs
@@ -4,16 +4,17 @@ using Microsoft.AspNetCore.Authorization;
using System.Collections.Generic;
using System.Threading.Tasks;
using Webshop.Application.DTOs.Products;
-using Webshop.Application.Services.Public.Interfaces; // <-- WICHTIGES USING HINZUFÜGEN
+using Webshop.Application.Services.Public.Interfaces;
+using Microsoft.AspNetCore.Http;
+using Webshop.Application;
namespace Webshop.Api.Controllers.Public
{
[ApiController]
- [Route("api/v1/public/[controller]")] // Route explizit gemacht für Klarheit
+ [Route("api/v1/public/[controller]")]
[AllowAnonymous]
public class ProductsController : ControllerBase
{
- // --- KORREKTUR: Abhängigkeit vom Interface, nicht von der Klasse ---
private readonly IProductService _productService;
public ProductsController(IProductService productService)
@@ -21,43 +22,35 @@ namespace Webshop.Api.Controllers.Public
_productService = productService;
}
- ///
- /// Ruft eine Liste aller öffentlichen, aktiven Produkte ab.
- ///
[HttpGet]
- [ProducesResponseType(typeof(IEnumerable), 200)]
- public async Task>> GetAllProducts()
+ [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)]
+ public async Task GetAllProducts()
{
- var products = await _productService.GetAllProductsAsync();
- return Ok(products);
+ var result = await _productService.GetAllProductsAsync();
+ return Ok(result.Value);
}
- ///
- /// Ruft ein einzelnes öffentliches Produkt anhand seines URL-Slugs ab.
- ///
- [HttpGet("{slug}")] // Ergibt die Route z.B. /api/v1/public/products/mein-produkt-slug
- [ProducesResponseType(typeof(ProductDto), 200)]
- [ProducesResponseType(404)] // Not Found
- public async Task> GetProductBySlug(string slug)
+ [HttpGet("{slug}")]
+ [ProducesResponseType(typeof(ProductDto), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
+ public async Task GetProductBySlug(string slug)
{
- var product = await _productService.GetProductBySlugAsync(slug);
+ var result = await _productService.GetProductBySlugAsync(slug);
- if (product == null)
+ return result.Type switch
{
- return NotFound();
- }
-
- return Ok(product);
+ ServiceResultType.Success => Ok(result.Value),
+ ServiceResultType.NotFound => NotFound(new { Message = result.ErrorMessage }),
+ _ => StatusCode(StatusCodes.Status500InternalServerError, "Ein unerwarteter Fehler ist aufgetreten.")
+ };
}
- ///
- /// Ruft eine Liste der Sonderangebote für die Startseite ab, sortiert nach Anzeigereihenfolge.
- ///
+
[HttpGet("featured")]
- [ProducesResponseType(typeof(IEnumerable), 200)]
- public async Task>> GetFeaturedProducts()
+ [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)]
+ public async Task GetFeaturedProducts()
{
- var products = await _productService.GetFeaturedProductsAsync();
- return Ok(products);
+ var result = await _productService.GetFeaturedProductsAsync();
+ return Ok(result.Value);
}
}
}
\ No newline at end of file
diff --git a/Webshop.Application/DTOs/Products/ProductDto.cs b/Webshop.Application/DTOs/Products/ProductDto.cs
index 6baa677..5494259 100644
--- a/Webshop.Application/DTOs/Products/ProductDto.cs
+++ b/Webshop.Application/DTOs/Products/ProductDto.cs
@@ -12,6 +12,7 @@ namespace Webshop.Application.DTOs.Products
public string Description { get; set; } = string.Empty;
public string SKU { get; set; } = string.Empty;
public decimal Price { get; set; }
+ public decimal? OldPrice { get; set; }
public bool IsActive { get; set; }
public bool IsInStock { get; set; }
public int StockQuantity { get; set; }
diff --git a/Webshop.Application/Services/Public/Interfaces/IProductService.cs b/Webshop.Application/Services/Public/Interfaces/IProductService.cs
index 035509b..6ecf3e4 100644
--- a/Webshop.Application/Services/Public/Interfaces/IProductService.cs
+++ b/Webshop.Application/Services/Public/Interfaces/IProductService.cs
@@ -1,15 +1,15 @@
-// RICHTIG - vollständig
+// src/Webshop.Application/Services/Public/Interfaces/IProductService.cs
using System.Collections.Generic;
using System.Threading.Tasks;
+using Webshop.Application;
using Webshop.Application.DTOs.Products;
namespace Webshop.Application.Services.Public.Interfaces
{
public interface IProductService
{
- Task> GetAllProductsAsync();
-
- Task GetProductBySlugAsync(string slug);
- Task> GetFeaturedProductsAsync(); // << NEU >>
+ Task>> GetAllProductsAsync();
+ Task> GetProductBySlugAsync(string slug);
+ Task>> GetFeaturedProductsAsync();
}
}
\ No newline at end of file
diff --git a/Webshop.Application/Services/Public/ProductService.cs b/Webshop.Application/Services/Public/ProductService.cs
index cc0de72..a745af1 100644
--- a/Webshop.Application/Services/Public/ProductService.cs
+++ b/Webshop.Application/Services/Public/ProductService.cs
@@ -3,10 +3,11 @@ using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using Webshop.Application;
using Webshop.Application.DTOs.Categorie;
using Webshop.Application.DTOs.Products;
using Webshop.Application.Services.Public.Interfaces;
-using Webshop.Domain.Interfaces;
+using Webshop.Domain.Entities;
using Webshop.Infrastructure.Data;
namespace Webshop.Application.Services.Public
@@ -20,77 +21,34 @@ namespace Webshop.Application.Services.Public
_context = context;
}
- public async Task> GetAllProductsAsync()
+ public async Task>> GetAllProductsAsync()
{
var products = await _context.Products
.Include(p => p.Productcategories).ThenInclude(pc => pc.categorie)
- .Include(p => p.Images) // Lade Bilder mit
+ .Include(p => p.Images)
.Where(p => p.IsActive)
.ToListAsync();
- return products.Select(p => new ProductDto
- {
- Id = p.Id,
- Name = p.Name,
- Description = p.ShortDescription,
- Price = p.Price,
- SKU = p.SKU,
- IsInStock = p.IsInStock,
- Slug = p.Slug,
- categories = p.Productcategories.Select(pc => new CategorieDto
- {
- Id = pc.categorie.Id,
- Name = pc.categorie.Name,
- Slug = pc.categorie.Slug
- }).ToList(),
- Images = p.Images.Select(img => new ProductImageDto
- {
- Id = img.Id,
- Url = img.Url,
- IsMainImage = img.IsMainImage,
- DisplayOrder = img.DisplayOrder
- }).ToList()
- }).ToList();
+ var dtos = products.Select(p => MapToDto(p, useShortDescription: true)).ToList();
+ return ServiceResult.Ok>(dtos);
}
- public async Task GetProductBySlugAsync(string slug)
+ public async Task> GetProductBySlugAsync(string slug)
{
var product = await _context.Products
.Include(p => p.Productcategories).ThenInclude(pc => pc.categorie)
- .Include(p => p.Images) // Lade Bilder mit
+ .Include(p => p.Images)
.FirstOrDefaultAsync(p => p.Slug == slug && p.IsActive);
if (product == null)
{
- return null;
+ return ServiceResult.Fail(ServiceResultType.NotFound, $"Produkt mit dem Slug '{slug}' wurde nicht gefunden.");
}
- return new ProductDto
- {
- Id = product.Id,
- Name = product.Name,
- Description = product.Description,
- Price = product.Price,
- SKU = product.SKU,
- IsInStock = product.IsInStock,
- Slug = product.Slug,
- categories = product.Productcategories.Select(pc => new CategorieDto
- {
- Id = pc.categorie.Id,
- Name = pc.categorie.Name,
- Slug = pc.categorie.Slug
- }).ToList(),
- Images = product.Images.Select(img => new ProductImageDto
- {
- Id = img.Id,
- Url = img.Url,
- IsMainImage = img.IsMainImage,
- DisplayOrder = img.DisplayOrder
- }).ToList()
- };
+ return ServiceResult.Ok(MapToDto(product, useShortDescription: false));
}
- public async Task> GetFeaturedProductsAsync()
+ public async Task>> GetFeaturedProductsAsync()
{
var products = await _context.Products
.Where(p => p.IsActive && p.IsFeatured)
@@ -99,32 +57,38 @@ namespace Webshop.Application.Services.Public
.Include(p => p.Productcategories).ThenInclude(pc => pc.categorie)
.ToListAsync();
- return products.Select(p => new ProductDto
+ var dtos = products.Select(p => MapToDto(p, useShortDescription: true)).ToList();
+ return ServiceResult.Ok>(dtos);
+ }
+
+ // Private Hilfsmethode, um Codeduplizierung zu vermeiden
+ private ProductDto MapToDto(Product product, bool useShortDescription)
+ {
+ return new ProductDto
{
- Id = p.Id,
- Name = p.Name,
- Description = p.ShortDescription, // Für die Startseite ist die Kurzbeschreibung ideal
- SKU = p.SKU,
- Price = p.Price,
- IsActive = p.IsActive,
- IsInStock = p.IsInStock,
- StockQuantity = p.StockQuantity,
- Slug = p.Slug,
- categories = p.Productcategories.Select(pc => new CategorieDto
+ Id = product.Id,
+ Name = product.Name,
+ Description = useShortDescription ? product.ShortDescription : product.Description,
+ Price = product.Price,
+ OldPrice = product.OldPrice,
+ SKU = product.SKU,
+ IsInStock = product.IsInStock,
+ StockQuantity = product.StockQuantity,
+ Slug = product.Slug,
+ categories = product.Productcategories.Select(pc => new CategorieDto
{
Id = pc.categorie.Id,
Name = pc.categorie.Name,
Slug = pc.categorie.Slug
}).ToList(),
- Images = p.Images.OrderBy(i => i.DisplayOrder).Select(img => new ProductImageDto
+ Images = product.Images.OrderBy(i => i.DisplayOrder).Select(img => new ProductImageDto
{
Id = img.Id,
Url = img.Url,
IsMainImage = img.IsMainImage,
DisplayOrder = img.DisplayOrder
}).ToList()
- }).ToList();
+ };
}
-
}
}
\ No newline at end of file