diff --git a/Webshop.Api/Controllers/Customers/ReviewsController.cs b/Webshop.Api/Controllers/Customers/ReviewsController.cs index d236891..dc33857 100644 --- a/Webshop.Api/Controllers/Customers/ReviewsController.cs +++ b/Webshop.Api/Controllers/Customers/ReviewsController.cs @@ -1,8 +1,10 @@ // src/Webshop.Api/Controllers/Customer/ReviewsController.cs using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System.Security.Claims; using System.Threading.Tasks; +using Webshop.Application; using Webshop.Application.DTOs.Reviews; using Webshop.Application.Services.Customers; @@ -21,16 +23,34 @@ namespace Webshop.Api.Controllers.Customer } [HttpPost] + [ProducesResponseType(typeof(ReviewDto), StatusCodes.Status201Created)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status409Conflict)] public async Task CreateReview([FromBody] CreateReviewDto reviewDto) { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + if (string.IsNullOrEmpty(userId)) + { + return Unauthorized(new { Message = "Benutzer konnte nicht identifiziert werden." }); + } + var result = await _customerReviewService.CreateReviewAsync(reviewDto, userId); - if (result.Type == Application.ServiceResultType.Success) + return result.Type switch { - return Ok(result.Value); - } - return BadRequest(new { Message = result.ErrorMessage }); + ServiceResultType.Success => CreatedAtAction(null, new { id = result.Value!.Id }, result.Value), // 201 Created + ServiceResultType.Unauthorized => Unauthorized(new { Message = result.ErrorMessage }), + ServiceResultType.Forbidden => Forbid(), // 403 Forbidden + ServiceResultType.Conflict => Conflict(new { Message = result.ErrorMessage }), // 409 Conflict + _ => BadRequest(new { Message = result.ErrorMessage }) // 400 for InvalidInput or other failures + }; } } } \ No newline at end of file diff --git a/Webshop.Application/Services/Customers/Interfaces/IReviewService.cs b/Webshop.Application/Services/Customers/Interfaces/IReviewService.cs index f667f4a..461ce1e 100644 --- a/Webshop.Application/Services/Customers/Interfaces/IReviewService.cs +++ b/Webshop.Application/Services/Customers/Interfaces/IReviewService.cs @@ -1,4 +1,4 @@ -// src/Webshop.Application/Services/Customers/Interfaces/IReviewService.cs +// src/Webshop.Application/Services/Customers/Interfaces/ICustomerReviewService.cs using System.Threading.Tasks; using Webshop.Application; using Webshop.Application.DTOs.Reviews; diff --git a/Webshop.Application/Services/Customers/ReviewService.cs b/Webshop.Application/Services/Customers/ReviewService.cs index b4114de..2ffd0e4 100644 --- a/Webshop.Application/Services/Customers/ReviewService.cs +++ b/Webshop.Application/Services/Customers/ReviewService.cs @@ -1,7 +1,9 @@ -// src/Webshop.Application/Services/Customers/ReviewService.cs +// src/Webshop.Application/Services/Customers/CustomerReviewService.cs +using Microsoft.EntityFrameworkCore; using System; using System.Linq; using System.Threading.Tasks; +using Webshop.Application; using Webshop.Application.DTOs.Reviews; using Webshop.Domain.Entities; using Webshop.Domain.Interfaces; @@ -25,12 +27,20 @@ namespace Webshop.Application.Services.Customers public async Task> CreateReviewAsync(CreateReviewDto reviewDto, string userId) { var customer = await _customerRepository.GetByUserIdAsync(userId); - if (customer == null) return ServiceResult.Fail(ServiceResultType.Unauthorized, "Kunde nicht gefunden."); + if (customer == null) + return ServiceResult.Fail(ServiceResultType.Unauthorized, "Kundenprofil nicht gefunden."); - // Business-Regel: Hat der Kunde dieses Produkt gekauft? - // bool hasPurchased = await _context.OrderItems - // .AnyAsync(oi => oi.ProductId == reviewDto.ProductId && oi.Order.CustomerId == customer.Id); - // if (!hasPurchased) return ServiceResult.Fail(ServiceResultType.Forbidden, "Sie können nur Produkte bewerten, die Sie gekauft haben."); + // Business-Regel 1: Hat der Kunde dieses Produkt bereits bewertet? + bool hasAlreadyReviewed = await _context.Reviews + .AnyAsync(r => r.ProductId == reviewDto.ProductId && r.CustomerId == customer.Id); + if (hasAlreadyReviewed) + return ServiceResult.Fail(ServiceResultType.Conflict, "Sie haben dieses Produkt bereits bewertet."); + + // Business-Regel 2: Hat der Kunde dieses Produkt überhaupt gekauft? + bool hasPurchased = await _context.OrderItems + .AnyAsync(oi => oi.ProductId == reviewDto.ProductId && oi.Order.CustomerId == customer.Id); + if (!hasPurchased) + return ServiceResult.Fail(ServiceResultType.Forbidden, "Sie können nur Produkte bewerten, die Sie auch gekauft haben."); var newReview = new Review { @@ -40,12 +50,24 @@ namespace Webshop.Application.Services.Customers Title = reviewDto.Title, Comment = reviewDto.Comment, ReviewDate = DateTimeOffset.UtcNow, - IsApproved = false // Bewertungen müssen vom Admin freigegeben werden + IsApproved = false // Bewertungen müssen standardmäßig vom Admin freigegeben werden }; await _reviewRepository.AddAsync(newReview); - var resultDto = new ReviewDto { /* Mapping */ }; + // Mapping vervollständigen, um das erstellte Objekt zurückzugeben + var resultDto = new ReviewDto + { + Id = newReview.Id, + ProductId = newReview.ProductId, + CustomerName = $"{customer.FirstName} {customer.LastName}".Trim(), + Rating = newReview.Rating, + Title = newReview.Title, + Comment = newReview.Comment, + ReviewDate = newReview.ReviewDate, + IsApproved = newReview.IsApproved + }; + return ServiceResult.Ok(resultDto); } }