test bilder erneut
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
// Auto-generiert von CreateWebshopFiles.ps1
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
// src/Webshop.Api/Controllers/Admin/AdminProductsController.cs
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
using Microsoft.AspNetCore.Http; // F<>r IFormFile
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Webshop.Application.DTOs.Products;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Webshop.Application.Services.Admin.Interfaces;
|
||||
|
||||
namespace Webshop.Api.Controllers.Admin
|
||||
@@ -39,25 +38,15 @@ namespace Webshop.Api.Controllers.Admin
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Consumes("multipart/form-data")]
|
||||
public async Task<ActionResult<AdminProductDto>> CreateAdminProduct([FromForm] CreateAdminProductDto productDto) // << NEU: [FromForm] und CreateAdminProductDto >>
|
||||
public async Task<ActionResult<AdminProductDto>> CreateAdminProduct([FromBody] CreateAdminProductDto productDto) // << ZUR<55>CK ZU [FromBody] >>
|
||||
{
|
||||
if (!ModelState.IsValid) return BadRequest(ModelState);
|
||||
|
||||
var createdProduct = await _adminProductService.CreateAdminProductAsync(productDto);
|
||||
|
||||
if (createdProduct == null)
|
||||
{
|
||||
// Hier k<>nnte eine spezifischere Fehlermeldung vom Service kommen
|
||||
return BadRequest("Produkt konnte nicht erstellt werden.");
|
||||
}
|
||||
|
||||
return CreatedAtAction(nameof(GetAdminProduct), new { id = createdProduct.Id }, createdProduct);
|
||||
}
|
||||
|
||||
|
||||
[HttpPut("{id}")]
|
||||
public async Task<IActionResult> UpdateAdminProduct(Guid id, [FromBody] UpdateAdminProductDto productDto)
|
||||
public async Task<IActionResult> UpdateAdminProduct(Guid id, [FromBody] UpdateAdminProductDto productDto) // << ZUR<55>CK ZU [FromBody] >>
|
||||
{
|
||||
if (id != productDto.Id) return BadRequest();
|
||||
if (!ModelState.IsValid) return BadRequest(ModelState);
|
||||
@@ -66,6 +55,7 @@ namespace Webshop.Api.Controllers.Admin
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
public async Task<IActionResult> DeleteAdminProduct(Guid id)
|
||||
{
|
||||
@@ -74,4 +64,4 @@ namespace Webshop.Api.Controllers.Admin
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ using Webshop.Domain.Identity;
|
||||
using Webshop.Domain.Interfaces;
|
||||
using Webshop.Infrastructure.Data;
|
||||
using Webshop.Infrastructure.Repositories;
|
||||
using Webshop.Infrastructure.Services;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@@ -108,6 +109,7 @@ builder.Services.AddScoped<IOrderService, OrderService>();
|
||||
builder.Services.AddScoped<IAddressService, AddressService>();
|
||||
builder.Services.AddScoped<ICheckoutService, CheckoutService>();
|
||||
builder.Services.AddScoped<IReviewService, ReviewService>();
|
||||
builder.Services.AddScoped<IFileStorageService, LocalFileStorageService>();
|
||||
|
||||
|
||||
// Externe Dienste (Resend)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// src/Webshop.Application/DTOs/Products/CreateAdminProductDto.cs
|
||||
using Microsoft.AspNetCore.Http; // Für IFormFile
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
@@ -21,13 +20,12 @@ namespace Webshop.Application.DTOs.Products
|
||||
[Required]
|
||||
public string Slug { get; set; }
|
||||
|
||||
// << NEU: Felder für den Bildupload >>
|
||||
public IFormFile? MainImageFile { get; set; }
|
||||
public List<IFormFile>? AdditionalImageFiles { get; set; }
|
||||
// << KORREKTUR: Felder für Bild-URLs, keine IFormFile >>
|
||||
public string? MainImageUrl { get; set; }
|
||||
public List<string>? AdditionalImageUrls { get; set; }
|
||||
|
||||
public List<Guid> CategorieIds { get; set; } = new List<Guid>();
|
||||
|
||||
// ... weitere Felder, die beim Erstellen benötigt werden (z.B. SupplierId, PurchasePrice etc.) ...
|
||||
public decimal? Weight { get; set; }
|
||||
public decimal? OldPrice { get; set; }
|
||||
public Guid? SupplierId { get; set; }
|
||||
|
||||
@@ -10,4 +10,4 @@ namespace Webshop.Application.DTOs.Products
|
||||
public bool IsMainImage { get; set; }
|
||||
public int DisplayOrder { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// src/Webshop.Application/DTOs/Products/UpdateAdminProductDto.cs
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
@@ -23,14 +22,12 @@ namespace Webshop.Application.DTOs.Products
|
||||
[Required]
|
||||
public string Slug { get; set; }
|
||||
|
||||
// << NEU: Felder für den Bildupload und -verwaltung >>
|
||||
public IFormFile? MainImageFile { get; set; } // Optional: Neues Hauptbild hochladen
|
||||
public List<IFormFile>? AdditionalImageFiles { get; set; } // Optional: Weitere Bilder hochladen
|
||||
public List<Guid>? ImagesToDelete { get; set; } // Liste der IDs von Bildern, die gelöscht werden sollen
|
||||
// << KORREKTUR: Felder für Bild-URLs >>
|
||||
public string? MainImageUrl { get; set; }
|
||||
public List<string>? AdditionalImageUrls { get; set; }
|
||||
|
||||
public List<Guid> CategorieIds { get; set; } = new List<Guid>();
|
||||
|
||||
// ... weitere Felder, die beim Aktualisieren benötigt werden ...
|
||||
public decimal? Weight { get; set; }
|
||||
public decimal? OldPrice { get; set; }
|
||||
public Guid? SupplierId { get; set; }
|
||||
|
||||
@@ -15,16 +15,13 @@ namespace Webshop.Application.Services.Admin
|
||||
public class AdminProductService : IAdminProductService
|
||||
{
|
||||
private readonly IProductRepository _productRepository;
|
||||
private readonly IFileStorageService _fileStorageService;
|
||||
private readonly ApplicationDbContext _context;
|
||||
|
||||
public AdminProductService(
|
||||
IProductRepository productRepository,
|
||||
IFileStorageService fileStorageService,
|
||||
ApplicationDbContext context)
|
||||
{
|
||||
_productRepository = productRepository;
|
||||
_fileStorageService = fileStorageService;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
@@ -33,6 +30,7 @@ namespace Webshop.Application.Services.Admin
|
||||
var products = await _context.Products
|
||||
.Include(p => p.Productcategories)
|
||||
.Include(p => p.Images)
|
||||
.OrderBy(p => p.Name)
|
||||
.ToListAsync();
|
||||
|
||||
return products.Select(p => new AdminProductDto
|
||||
@@ -53,7 +51,7 @@ namespace Webshop.Application.Services.Admin
|
||||
SupplierId = p.SupplierId,
|
||||
PurchasePrice = p.PurchasePrice,
|
||||
categorieIds = p.Productcategories.Select(pc => pc.categorieId).ToList(),
|
||||
Images = p.Images.Select(img => new ProductImageDto
|
||||
Images = p.Images.OrderBy(i => i.DisplayOrder).Select(img => new ProductImageDto
|
||||
{
|
||||
Id = img.Id,
|
||||
Url = img.Url,
|
||||
@@ -90,7 +88,7 @@ namespace Webshop.Application.Services.Admin
|
||||
SupplierId = product.SupplierId,
|
||||
PurchasePrice = product.PurchasePrice,
|
||||
categorieIds = product.Productcategories.Select(pc => pc.categorieId).ToList(),
|
||||
Images = product.Images.Select(img => new ProductImageDto
|
||||
Images = product.Images.OrderBy(i => i.DisplayOrder).Select(img => new ProductImageDto
|
||||
{
|
||||
Id = img.Id,
|
||||
Url = img.Url,
|
||||
@@ -100,23 +98,19 @@ namespace Webshop.Application.Services.Admin
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<AdminProductDto> CreateAdminProductAsync(CreateAdminProductDto productDto)
|
||||
public async Task<AdminProductDto?> CreateAdminProductAsync(CreateAdminProductDto productDto)
|
||||
{
|
||||
var images = new List<ProductImage>();
|
||||
|
||||
if (productDto.MainImageFile != null)
|
||||
if (!string.IsNullOrEmpty(productDto.MainImageUrl))
|
||||
{
|
||||
await using var stream = productDto.MainImageFile.OpenReadStream();
|
||||
var url = await _fileStorageService.SaveFileAsync(stream, productDto.MainImageFile.FileName, productDto.MainImageFile.ContentType);
|
||||
images.Add(new ProductImage { Url = url, IsMainImage = true, DisplayOrder = 1 });
|
||||
images.Add(new ProductImage { Url = productDto.MainImageUrl, IsMainImage = true, DisplayOrder = 1 });
|
||||
}
|
||||
if (productDto.AdditionalImageFiles != null)
|
||||
if (productDto.AdditionalImageUrls != null)
|
||||
{
|
||||
int order = 2;
|
||||
foreach (var file in productDto.AdditionalImageFiles)
|
||||
foreach (var url in productDto.AdditionalImageUrls)
|
||||
{
|
||||
await using var stream = file.OpenReadStream();
|
||||
var url = await _fileStorageService.SaveFileAsync(stream, file.FileName, file.ContentType);
|
||||
images.Add(new ProductImage { Url = url, IsMainImage = false, DisplayOrder = order++ });
|
||||
}
|
||||
}
|
||||
@@ -130,13 +124,17 @@ namespace Webshop.Application.Services.Admin
|
||||
IsActive = productDto.IsActive,
|
||||
StockQuantity = productDto.StockQuantity,
|
||||
Slug = productDto.Slug,
|
||||
Weight = productDto.Weight,
|
||||
OldPrice = productDto.OldPrice,
|
||||
SupplierId = productDto.SupplierId,
|
||||
PurchasePrice = productDto.PurchasePrice,
|
||||
Images = images,
|
||||
Productcategories = productDto.CategorieIds.Select(cId => new Productcategorie { categorieId = cId }).ToList()
|
||||
};
|
||||
|
||||
await _productRepository.AddProductAsync(newProduct);
|
||||
|
||||
return (await GetAdminProductByIdAsync(newProduct.Id))!;
|
||||
return await GetAdminProductByIdAsync(newProduct.Id);
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAdminProductAsync(UpdateAdminProductDto productDto)
|
||||
@@ -148,34 +146,44 @@ namespace Webshop.Application.Services.Admin
|
||||
|
||||
if (existingProduct == null) return false;
|
||||
|
||||
if (productDto.ImagesToDelete != null)
|
||||
{
|
||||
var imagesToRemove = existingProduct.Images.Where(img => productDto.ImagesToDelete.Contains(img.Id)).ToList();
|
||||
_context.ProductImages.RemoveRange(imagesToRemove);
|
||||
}
|
||||
if (productDto.MainImageFile != null)
|
||||
{
|
||||
var existingMainImage = existingProduct.Images.FirstOrDefault(img => img.IsMainImage);
|
||||
if (existingMainImage != null) _context.ProductImages.Remove(existingMainImage);
|
||||
// Basisdaten aktualisieren
|
||||
existingProduct.Name = productDto.Name;
|
||||
existingProduct.Description = productDto.Description;
|
||||
existingProduct.SKU = productDto.SKU;
|
||||
existingProduct.Price = productDto.Price;
|
||||
existingProduct.IsActive = productDto.IsActive;
|
||||
existingProduct.StockQuantity = productDto.StockQuantity;
|
||||
existingProduct.Slug = productDto.Slug;
|
||||
existingProduct.Weight = productDto.Weight;
|
||||
existingProduct.OldPrice = productDto.OldPrice;
|
||||
existingProduct.SupplierId = productDto.SupplierId;
|
||||
existingProduct.PurchasePrice = productDto.PurchasePrice;
|
||||
existingProduct.LastModifiedDate = DateTimeOffset.UtcNow;
|
||||
|
||||
await using var stream = productDto.MainImageFile.OpenReadStream();
|
||||
var url = await _fileStorageService.SaveFileAsync(stream, productDto.MainImageFile.FileName, productDto.MainImageFile.ContentType);
|
||||
existingProduct.Images.Add(new ProductImage { Url = url, IsMainImage = true, DisplayOrder = 1 });
|
||||
}
|
||||
if (productDto.AdditionalImageFiles != null)
|
||||
// Kategorien synchronisieren
|
||||
existingProduct.Productcategories.Clear();
|
||||
if (productDto.CategorieIds != null)
|
||||
{
|
||||
int displayOrder = (existingProduct.Images.Any() ? existingProduct.Images.Max(i => i.DisplayOrder) : 0) + 1;
|
||||
foreach (var file in productDto.AdditionalImageFiles)
|
||||
foreach (var categorieId in productDto.CategorieIds)
|
||||
{
|
||||
await using var stream = file.OpenReadStream();
|
||||
var url = await _fileStorageService.SaveFileAsync(stream, file.FileName, file.ContentType);
|
||||
existingProduct.Images.Add(new ProductImage { Url = url, IsMainImage = false, DisplayOrder = displayOrder++ });
|
||||
existingProduct.Productcategories.Add(new Productcategorie { categorieId = categorieId });
|
||||
}
|
||||
}
|
||||
|
||||
existingProduct.Name = productDto.Name;
|
||||
existingProduct.Description = productDto.Description;
|
||||
// ... (restliche Felder aktualisieren) ...
|
||||
// Bilder synchronisieren
|
||||
existingProduct.Images.Clear();
|
||||
if (!string.IsNullOrEmpty(productDto.MainImageUrl))
|
||||
{
|
||||
existingProduct.Images.Add(new ProductImage { Url = productDto.MainImageUrl, IsMainImage = true, DisplayOrder = 1 });
|
||||
}
|
||||
if (productDto.AdditionalImageUrls != null)
|
||||
{
|
||||
int order = 2;
|
||||
foreach (var url in productDto.AdditionalImageUrls)
|
||||
{
|
||||
existingProduct.Images.Add(new ProductImage { Url = url, IsMainImage = false, DisplayOrder = order++ });
|
||||
}
|
||||
}
|
||||
|
||||
await _productRepository.UpdateProductAsync(existingProduct);
|
||||
return true;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// src/Webshop.Application/Services/Admin/Interfaces/IAdminProductService.cs
|
||||
// src/Webshop.Application/Services/Admin/IAdminProductService.cs
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Webshop.Application.DTOs.Products;
|
||||
@@ -9,8 +10,8 @@ namespace Webshop.Application.Services.Admin.Interfaces
|
||||
{
|
||||
Task<IEnumerable<AdminProductDto>> GetAllAdminProductsAsync();
|
||||
Task<AdminProductDto?> GetAdminProductByIdAsync(Guid id);
|
||||
Task<AdminProductDto> CreateAdminProductAsync(CreateAdminProductDto productDto); // << NEUER TYP >>
|
||||
Task<bool> UpdateAdminProductAsync(UpdateAdminProductDto productDto); // << NEUER TYP >>
|
||||
Task<AdminProductDto?> CreateAdminProductAsync(CreateAdminProductDto productDto); // << DTO-TYP GEÄNDERT >>
|
||||
Task<bool> UpdateAdminProductAsync(UpdateAdminProductDto productDto); // << DTO-TYP GEÄNDERT >>
|
||||
Task<bool> DeleteAdminProductAsync(Guid id);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user