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