try
This commit is contained in:
@@ -1,15 +1,19 @@
|
||||
// src/Webshop.Api/Controllers/Customer/ProfileController.cs
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
using Webshop.Application.DTOs; // CustomerDto
|
||||
using Webshop.Application.DTOs.Auth; // ChangePasswordRequestDto
|
||||
using Webshop.Application.DTOs.Customers; // UpdateCustomerProfileDto
|
||||
using Webshop.Application.Services;
|
||||
using System.Threading.Tasks;
|
||||
using Webshop.Application.DTOs.Customers;
|
||||
using Webshop.Application.Services.Customers.Interfaces;
|
||||
using Webshop.Application.Services.Customers;
|
||||
|
||||
namespace Webshop.Api.Controllers.Customers
|
||||
namespace Webshop.Api.Controllers.Customer
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/v1/customer/profile")] // Eindeutige Route f<>r das Profil
|
||||
[Authorize(Roles = "Customer")] // Nur f<>r eingeloggte Kunden!
|
||||
[Route("api/v1/customer/[controller]")] // z.B. /api/v1/customer/profile
|
||||
[Authorize(Roles = "Customer")]
|
||||
public class ProfileController : ControllerBase
|
||||
{
|
||||
private readonly ICustomerService _customerService;
|
||||
@@ -19,33 +23,49 @@ namespace Webshop.Api.Controllers.Customers
|
||||
_customerService = customerService;
|
||||
}
|
||||
|
||||
// Hilfsmethode, um die ID des eingeloggten Benutzers aus dem Token zu holen
|
||||
private string GetUserId() => User.FindFirstValue(ClaimTypes.NameIdentifier)!;
|
||||
|
||||
[HttpGet("me")] // GET /api/v1/customer/profile/me
|
||||
[HttpGet("me")] // /api/v1/customer/profile/me
|
||||
public async Task<ActionResult<CustomerDto>> GetMyProfile()
|
||||
{
|
||||
var userId = GetUserId();
|
||||
var profile = await _customerService.GetMyProfileAsync(userId);
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
if (string.IsNullOrEmpty(userId)) return Unauthorized(new { Message = "Benutzer-ID nicht im Token gefunden." });
|
||||
|
||||
if (profile == null)
|
||||
{
|
||||
return NotFound("Kundenprofil nicht gefunden.");
|
||||
}
|
||||
return Ok(profile);
|
||||
var customerProfile = await _customerService.GetMyProfileAsync(userId);
|
||||
if (customerProfile == null) return NotFound(new { Message = "Kundenprofil nicht gefunden. Bitte erstellen Sie es." });
|
||||
|
||||
return Ok(customerProfile);
|
||||
}
|
||||
|
||||
[HttpPut("me")] // PUT /api/v1/customer/profile/me
|
||||
public async Task<IActionResult> UpdateMyProfile([FromBody] UpdateCustomerProfileDto profileDto)
|
||||
[HttpPost("change-password")] // /api/v1/customer/profile/change-password
|
||||
public async Task<IActionResult> ChangePassword([FromBody] ChangePasswordRequestDto request)
|
||||
{
|
||||
var userId = GetUserId();
|
||||
var success = await _customerService.UpdateMyProfileAsync(userId, profileDto);
|
||||
if (!ModelState.IsValid) return BadRequest(ModelState);
|
||||
|
||||
if (!success)
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
if (string.IsNullOrEmpty(userId)) return Unauthorized(new { Message = "Benutzer-ID nicht im Token gefunden." });
|
||||
|
||||
var (success, errorMessage) = await _customerService.ChangePasswordAsync(userId, request);
|
||||
|
||||
if (!success) return BadRequest(new { Message = errorMessage });
|
||||
|
||||
return Ok(new { Message = "Passwort erfolgreich ge<67>ndert. Bitte melden Sie sich mit dem neuen Passwort an." });
|
||||
}
|
||||
|
||||
// << NEUER/AKTUALISIERTER ENDPUNKT F<>R PROFIL-AKTUALISIERUNG >>
|
||||
[HttpPost("update-profile")] // /api/v1/customer/profile/update-profile
|
||||
public async Task<IActionResult> UpdateProfile([FromBody] UpdateCustomerProfileDto request)
|
||||
{
|
||||
return NotFound("Kundenprofil nicht gefunden.");
|
||||
}
|
||||
return NoContent(); // Standardantwort f<>r ein erfolgreiches Update
|
||||
if (!ModelState.IsValid) return BadRequest(ModelState);
|
||||
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
if (string.IsNullOrEmpty(userId)) return Unauthorized(new { Message = "Benutzer-ID nicht im Token gefunden." });
|
||||
|
||||
var (success, errorMessage) = await _customerService.UpdateMyProfileAsync(userId, request);
|
||||
|
||||
if (!success) return BadRequest(new { Message = errorMessage });
|
||||
|
||||
return Ok(new { Message = "Profil erfolgreich aktualisiert." });
|
||||
}
|
||||
|
||||
// << ENTFERNT: UpdateContactInfo Endpoint >>
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ using Webshop.Application.Services.Admin.Interfaces;
|
||||
using Webshop.Application.Services.Public.Interfaces;
|
||||
using Webshop.Application.Services.Customers.Interfaces;
|
||||
using Webshop.Application.Services.Customers;
|
||||
using Webshop.Domain.Identity;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@@ -136,6 +137,7 @@ builder.Services.AddSwaggerGen(c =>
|
||||
|
||||
var app = builder.Build(); // <-- Hier wird die App gebaut
|
||||
|
||||
// OPTIONALE BL<42>CKE F<>R MIGRATION UND BENUTZERINITIALISIERUNG - DIESER CODE WIRD VOR APP.RUN() AUSGEF<45>HRT
|
||||
// OPTIONALE BL<42>CKE F<>R MIGRATION UND BENUTZERINITIALISIERUNG - DIESER CODE WIRD VOR APP.RUN() AUSGEF<45>HRT
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
@@ -150,7 +152,7 @@ using (var scope = app.Services.CreateScope())
|
||||
// Dieser Block erstellt Rollen und initiale Benutzer, falls sie noch nicht existieren.
|
||||
// BITTE ENTFERNEN ODER KOMMENTIEREN SIE DIESEN BLOCK AUS, NACHDEM SIE IHRE ERSTEN BENUTZER ERSTELLT HABEN!
|
||||
var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>();
|
||||
var userManager = services.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
var userManager = services.GetRequiredService<UserManager<ApplicationUser>>(); // << KORREKT: UserManager f<>r ApplicationUser >>
|
||||
|
||||
string[] roleNames = { "Admin", "Customer" };
|
||||
|
||||
@@ -162,23 +164,39 @@ using (var scope = app.Services.CreateScope())
|
||||
}
|
||||
}
|
||||
|
||||
// Erstelle einen initialen Admin-Benutzer
|
||||
var adminUser = await userManager.FindByEmailAsync("admin@yourwebshop.com");
|
||||
// Erstelle einen initialen Admin-Benutzer und sein Customer-Profil
|
||||
var adminUser = await userManager.FindByEmailAsync("admin@yourwebshop.com"); // << ANPASSEN >>
|
||||
if (adminUser == null)
|
||||
{
|
||||
// Erstellen Sie hier eine Instanz von ApplicationUser
|
||||
adminUser = new ApplicationUser
|
||||
adminUser = new ApplicationUser // << KORREKT: ERSTELLT ApplicationUser >>
|
||||
{
|
||||
UserName = "admin@yourwebshop.com",
|
||||
Email = "admin@yourwebshop.com",
|
||||
UserName = "admin@yourwebshop.com", // << ANPASSEN >>
|
||||
Email = "admin@yourwebshop.com", // << ANPASSEN >>
|
||||
EmailConfirmed = true,
|
||||
CreatedDate = DateTimeOffset.UtcNow // Setzen Sie Ihr neues Feld!
|
||||
CreatedDate = DateTimeOffset.UtcNow, // Custom Property auf ApplicationUser
|
||||
LastActive = DateTimeOffset.UtcNow // Custom Property auf ApplicationUser
|
||||
};
|
||||
var createAdmin = await userManager.CreateAsync(adminUser, "SecureAdminPass123!");
|
||||
var createAdmin = await userManager.CreateAsync(adminUser, "SecureAdminPass123!"); // << ANPASSEN >>
|
||||
if (createAdmin.Succeeded)
|
||||
{
|
||||
await userManager.AddToRoleAsync(adminUser, "Admin");
|
||||
Console.WriteLine("Admin user created.");
|
||||
|
||||
// Erstelle Customer-Profil f<>r Admin (falls Admins auch Kundenprofile haben sollen)
|
||||
var adminCustomerProfile = await context.Customers.FirstOrDefaultAsync(c => c.AspNetUserId == adminUser.Id); // << KORREKT: SUCHT NACH AspNetUserId >>
|
||||
if (adminCustomerProfile == null)
|
||||
{
|
||||
adminCustomerProfile = new Webshop.Domain.Entities.Customer
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
AspNetUserId = adminUser.Id, // << KORREKT: VERKN<4B>PFUNG <20>BER AspNetUserId >>
|
||||
FirstName = "Admin",
|
||||
LastName = "User"
|
||||
};
|
||||
context.Customers.Add(adminCustomerProfile);
|
||||
await context.SaveChangesAsync();
|
||||
Console.WriteLine("Admin's Customer profile created.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -186,29 +204,46 @@ using (var scope = app.Services.CreateScope())
|
||||
}
|
||||
}
|
||||
|
||||
// Erstelle einen initialen Kunden-Benutzer
|
||||
var customerUser = await userManager.FindByEmailAsync("customer@yourwebshop.com");
|
||||
// Erstelle einen initialen Kunden-Benutzer und sein Customer-Profil (KOMBINIERT)
|
||||
var customerUser = await userManager.FindByEmailAsync("customer@yourwebshop.com"); // << ANPASSEN >>
|
||||
if (customerUser == null)
|
||||
{
|
||||
// Erstellen Sie auch hier eine Instanz von ApplicationUser
|
||||
customerUser = new ApplicationUser
|
||||
customerUser = new ApplicationUser // << KORREKT: ERSTELLT ApplicationUser >>
|
||||
{
|
||||
UserName = "customer@yourwebshop.com",
|
||||
Email = "customer@yourwebshop.com",
|
||||
UserName = "customer@yourwebshop.com", // << ANPASSEN >>
|
||||
Email = "customer@yourwebshop.com", // << ANPASSEN >>
|
||||
EmailConfirmed = true,
|
||||
CreatedDate = DateTimeOffset.UtcNow // Setzen Sie Ihr neues Feld!
|
||||
CreatedDate = DateTimeOffset.UtcNow, // Custom Property auf ApplicationUser
|
||||
LastActive = DateTimeOffset.UtcNow // Custom Property auf ApplicationUser
|
||||
};
|
||||
var createCustomer = await userManager.CreateAsync(customerUser, "SecureCustomerPass123!");
|
||||
var createCustomer = await userManager.CreateAsync(customerUser, "SecureCustomerPass123!"); // << ANPASSEN >>
|
||||
if (createCustomer.Succeeded)
|
||||
{
|
||||
await userManager.AddToRoleAsync(customerUser, "Customer");
|
||||
Console.WriteLine("Customer user created.");
|
||||
|
||||
// Kombinierter Teil: Customer-Profil erstellen, direkt nach IdentityUser-Erstellung
|
||||
var customerProfile = await context.Customers.FirstOrDefaultAsync(c => c.AspNetUserId == customerUser.Id); // << KORREKT: SUCHT NACH AspNetUserId >>
|
||||
if (customerProfile == null)
|
||||
{
|
||||
customerProfile = new Webshop.Domain.Entities.Customer
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
AspNetUserId = customerUser.Id,
|
||||
FirstName = "Test",
|
||||
LastName = "Kunde"
|
||||
};
|
||||
context.Customers.Add(customerProfile);
|
||||
await context.SaveChangesAsync();
|
||||
Console.WriteLine("Customer profile created for new customer user.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Error creating customer user: {string.Join(", ", createCustomer.Errors.Select(e => e.Description))}");
|
||||
}
|
||||
}
|
||||
// --- ENDE DES TEMPOR<4F>REN SETUP-BLOCKS ---
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ using Webshop.Application.DTOs.Products;
|
||||
using Webshop.Application.DTOs.Payments;
|
||||
using Webshop.Application.DTOs.Orders;
|
||||
using Webshop.Application.DTOs.Discounts;
|
||||
using Webshop.Application.DTOs.Categorys; // Für Guid.NewGuid()
|
||||
using Webshop.Application.DTOs.Categorys;
|
||||
|
||||
namespace Webshop.Api.SwaggerFilters
|
||||
{
|
||||
|
||||
19
Webshop.Application/DTOs/Auth/ChangePasswordRequestDto.cs
Normal file
19
Webshop.Application/DTOs/Auth/ChangePasswordRequestDto.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// src/Webshop.Application/DTOs/Auth/ChangePasswordRequestDto.cs
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Webshop.Application.DTOs.Auth
|
||||
{
|
||||
public class ChangePasswordRequestDto
|
||||
{
|
||||
[Required(ErrorMessage = "Altes Passwort ist erforderlich.")]
|
||||
public string OldPassword { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "Neues Passwort ist erforderlich.")]
|
||||
[MinLength(6, ErrorMessage = "Passwort muss mindestens 6 Zeichen lang sein.")]
|
||||
public string NewPassword { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "Passwortbestätigung ist erforderlich.")]
|
||||
[Compare("NewPassword", ErrorMessage = "Neues Passwort und Bestätigung stimmen nicht überein.")]
|
||||
public string ConfirmNewPassword { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,26 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
// src/Webshop.Application/DTOs/Customers/UpdateCustomerProfileDto.cs
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Webshop.Application.DTOs.Customers
|
||||
{
|
||||
public class UpdateCustomerProfileDto
|
||||
{
|
||||
[Required(ErrorMessage = "Vorname ist erforderlich.")]
|
||||
[MaxLength(100)]
|
||||
[StringLength(100)]
|
||||
public string FirstName { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "Nachname ist erforderlich.")]
|
||||
[MaxLength(100)]
|
||||
[StringLength(100)]
|
||||
public string LastName { get; set; } = string.Empty;
|
||||
|
||||
[Phone(ErrorMessage = "Ungültiges Telefonnummernformat.")]
|
||||
public string? PhoneNumber { get; set; } // Telefonnummer des Benutzers
|
||||
|
||||
[EmailAddress(ErrorMessage = "Ungültiges E-Mail-Format.")]
|
||||
public string? Email { get; set; } // E-Mail des Benutzers
|
||||
|
||||
// Optional, aber gute Sicherheitspraxis: Aktuelles Passwort zur Bestätigung sensibler Änderungen
|
||||
[Required(ErrorMessage = "Aktuelles Passwort ist zur Bestätigung erforderlich.")]
|
||||
public string CurrentPassword { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// src/Webshop.Application/DTOs/Users/AdminResetPasswordRequestDto.cs
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Webshop.Application.DTOs.Users
|
||||
{
|
||||
public class AdminResetPasswordRequestDto
|
||||
{
|
||||
[Required(ErrorMessage = "Benutzer-ID ist erforderlich.")]
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "Neues Passwort ist erforderlich.")]
|
||||
[MinLength(6, ErrorMessage = "Passwort muss mindestens 6 Zeichen lang sein.")]
|
||||
public string NewPassword { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "Passwortbestätigung ist erforderlich.")]
|
||||
[Compare("NewPassword", ErrorMessage = "Neues Passwort und Bestätigung stimmen nicht überein.")]
|
||||
public string ConfirmNewPassword { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,25 @@
|
||||
// src/Webshop.Application/DTOs/Users/UserDto.cs
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Webshop.Application.DTOs.Users
|
||||
{
|
||||
public class UserDto
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string Email { get; set; } = string.Empty;
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
public List<string> Roles { get; set; } = new List<string>();
|
||||
public DateTimeOffset CreatedDate { get; set; }
|
||||
public bool EmailConfirmed { get; set; }
|
||||
public string Id { get; set; } = string.Empty; // Vom ApplicationUser.Id
|
||||
public string Email { get; set; } = string.Empty; // Vom ApplicationUser.Email
|
||||
public string UserName { get; set; } = string.Empty; // Vom ApplicationUser.UserName
|
||||
public List<string> Roles { get; set; } = new List<string>(); // Aus Identity-System
|
||||
public DateTimeOffset CreatedDate { get; set; } // Vom ApplicationUser.CreatedDate
|
||||
public bool EmailConfirmed { get; set; } // Vom ApplicationUser.EmailConfirmed
|
||||
|
||||
// Hinzugef<65>gte Felder
|
||||
public DateTimeOffset? LastActive { get; set; }
|
||||
public string FirstName { get; set; } = string.Empty;
|
||||
public string LastName { get; set; } = string.Empty;
|
||||
public DateTimeOffset? LastActive { get; set; } // Vom ApplicationUser.LastActive
|
||||
public string? PhoneNumber { get; set; } // Vom ApplicationUser.PhoneNumber
|
||||
|
||||
// << NEU: Customer-Felder, die NICHT in ApplicationUser sind >>
|
||||
public string FirstName { get; set; } = string.Empty; // Vom Customer.FirstName
|
||||
public string LastName { get; set; } = string.Empty; // Vom Customer.LastName
|
||||
public Guid? DefaultShippingAddressId { get; set; } // Vom Customer
|
||||
public Guid? DefaultBillingAddressId { get; set; } // Vom Customer
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using System.Linq;
|
||||
using Webshop.Application.DTOs.Products;
|
||||
using Webshop.Application.Services.Admin.Interfaces; // F<>r Select
|
||||
|
||||
|
||||
namespace Webshop.Application.Services.Admin
|
||||
{
|
||||
public class AdminProductService : IAdminProductService // Sicherstellen, dass IAdminProductService implementiert wird
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Webshop.Application.DTOs.Suppliers;
|
||||
using Webshop.Application.Services.Admin.Interfaces;
|
||||
using Webshop.Domain.Identity;
|
||||
|
||||
namespace Webshop.Application.Services.Admin
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ using Webshop.Application.DTOs.Users;
|
||||
using Webshop.Application.Services.Admin.Interfaces;
|
||||
using Webshop.Domain.Entities;
|
||||
using Webshop.Infrastructure.Data; // WICHTIG: Stellt sicher, dass ApplicationDbContext gefunden wird.
|
||||
using Webshop.Domain.Identity;
|
||||
|
||||
namespace Webshop.Application.Services.Admin
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
// src/Webshop.Application/Services/Admin/Interfaces/IAdminUserService.cs
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Webshop.Application.DTOs.Users;
|
||||
|
||||
|
||||
@@ -1,52 +1,122 @@
|
||||
// src/Webshop.Application/Services/Customers/CustomerService.cs
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Threading.Tasks;
|
||||
using Webshop.Application.DTOs.Customers;
|
||||
using Webshop.Application.Services.Customers.Interfaces;
|
||||
using Webshop.Domain.Interfaces; // Wichtig für ICustomerRepository
|
||||
using Webshop.Application.DTOs; // CustomerDto
|
||||
using Webshop.Application.DTOs.Auth; // ChangePasswordRequestDto
|
||||
using Webshop.Application.DTOs.Customers; // UpdateCustomerProfileDto
|
||||
using Webshop.Domain.Entities; // Customer Entity
|
||||
using Webshop.Domain.Interfaces; // ICustomerRepository
|
||||
using Webshop.Domain.Identity; // Für ApplicationUser
|
||||
using System.Linq; // Für Select
|
||||
using System.Collections.Generic; // Für IEnumerable
|
||||
|
||||
namespace Webshop.Application.Services.Customers
|
||||
{
|
||||
public class CustomerService : ICustomerService
|
||||
{
|
||||
private readonly ICustomerRepository _customerRepository;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
|
||||
public CustomerService(ICustomerRepository customerRepository)
|
||||
public CustomerService(ICustomerRepository customerRepository, UserManager<ApplicationUser> userManager)
|
||||
{
|
||||
_customerRepository = customerRepository;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
public async Task<CustomerDto?> GetMyProfileAsync(string userId)
|
||||
{
|
||||
var customer = await _customerRepository.GetByUserIdAsync(userId);
|
||||
if (customer == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (customer == null) return null;
|
||||
|
||||
var identityUser = await _userManager.FindByIdAsync(userId);
|
||||
if (identityUser == null) return null;
|
||||
|
||||
// Mappe die Entity auf das CustomerDto
|
||||
return new CustomerDto
|
||||
{
|
||||
Id = customer.Id,
|
||||
UserId = customer.AspNetUserId,
|
||||
FirstName = customer.FirstName,
|
||||
LastName = customer.LastName,
|
||||
// Fügen Sie hier weitere Felder hinzu, die der Kunde sehen soll (Email, Phone etc.)
|
||||
Email = identityUser.Email ?? string.Empty, // E-Mail vom ApplicationUser
|
||||
PhoneNumber = identityUser.PhoneNumber, // Telefonnummer vom ApplicationUser
|
||||
DefaultShippingAddressId = customer.DefaultShippingAddressId,
|
||||
DefaultBillingAddressId = customer.DefaultBillingAddressId
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateMyProfileAsync(string userId, UpdateCustomerProfileDto profileDto)
|
||||
public async Task<(bool Success, string ErrorMessage)> ChangePasswordAsync(string userId, ChangePasswordRequestDto request)
|
||||
{
|
||||
var user = await _userManager.FindByIdAsync(userId);
|
||||
if (user == null) return (false, "Benutzer nicht gefunden.");
|
||||
|
||||
var result = await _userManager.ChangePasswordAsync(user, request.OldPassword, request.NewPassword);
|
||||
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
var errors = string.Join(" ", result.Errors.Select(e => e.Description));
|
||||
return (false, errors);
|
||||
}
|
||||
|
||||
return (true, "Passwort erfolgreich geändert.");
|
||||
}
|
||||
|
||||
// << NEUE IMPLEMENTIERUNG: UpdateMyProfileAsync verarbeitet alle Felder >>
|
||||
public async Task<(bool Success, string ErrorMessage)> UpdateMyProfileAsync(string userId, UpdateCustomerProfileDto profileDto)
|
||||
{
|
||||
var customer = await _customerRepository.GetByUserIdAsync(userId);
|
||||
if (customer == null)
|
||||
if (customer == null) return (false, "Kundenprofil nicht gefunden.");
|
||||
|
||||
var identityUser = await _userManager.FindByIdAsync(userId);
|
||||
if (identityUser == null) return (false, "Benutzerkonto nicht gefunden.");
|
||||
|
||||
// 1. Aktuelles Passwort prüfen (für alle sensiblen Änderungen)
|
||||
if (!await _userManager.CheckPasswordAsync(identityUser, profileDto.CurrentPassword))
|
||||
{
|
||||
return false; // Kunde nicht gefunden
|
||||
return (false, "Falsches aktuelles Passwort zur Bestätigung.");
|
||||
}
|
||||
|
||||
// Aktualisiere die Felder
|
||||
// 2. Felder der Customer-Entität aktualisieren (FirstName, LastName)
|
||||
customer.FirstName = profileDto.FirstName;
|
||||
customer.LastName = profileDto.LastName;
|
||||
// customer.PhoneNumber = profileDto.PhoneNumber; // Entfernt, da es jetzt in ApplicationUser zentralisiert ist
|
||||
await _customerRepository.UpdateAsync(customer); // Speichert Änderungen im Customer-Profil
|
||||
|
||||
await _customerRepository.UpdateAsync(customer);
|
||||
return true;
|
||||
// 3. Felder des ApplicationUser (IdentityUser) aktualisieren (Email, PhoneNumber)
|
||||
bool identityUserChanged = false;
|
||||
|
||||
// E-Mail aktualisieren (wenn anders und nicht leer)
|
||||
if (!string.IsNullOrEmpty(profileDto.Email) && identityUser.Email != profileDto.Email)
|
||||
{
|
||||
identityUser.Email = profileDto.Email;
|
||||
identityUser.NormalizedEmail = _userManager.NormalizeEmail(profileDto.Email);
|
||||
identityUser.UserName = profileDto.Email; // Oft wird der UserName auch mit der E-Mail synchronisiert
|
||||
identityUser.NormalizedUserName = _userManager.NormalizeName(profileDto.Email);
|
||||
// Optional: user.EmailConfirmed = false; wenn Sie Bestätigungs-E-Mails senden
|
||||
identityUserChanged = true;
|
||||
}
|
||||
|
||||
// Telefonnummer aktualisieren (wenn anders und nicht leer)
|
||||
if (!string.IsNullOrEmpty(profileDto.PhoneNumber) && identityUser.PhoneNumber != profileDto.PhoneNumber)
|
||||
{
|
||||
identityUser.PhoneNumber = profileDto.PhoneNumber;
|
||||
// Optional: identityUser.PhoneNumberConfirmed = false;
|
||||
identityUserChanged = true;
|
||||
}
|
||||
|
||||
if (identityUserChanged)
|
||||
{
|
||||
var updateResult = await _userManager.UpdateAsync(identityUser);
|
||||
if (!updateResult.Succeeded)
|
||||
{
|
||||
var errors = string.Join(" ", updateResult.Errors.Select(e => e.Description));
|
||||
return (false, $"Fehler beim Aktualisieren der Kontaktdaten: {errors}");
|
||||
}
|
||||
}
|
||||
|
||||
return (true, "Profil und Kontaktdaten erfolgreich aktualisiert.");
|
||||
}
|
||||
|
||||
// << ENTFERNT: UpdateMyContactInfoAsync >>
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,16 @@
|
||||
// src/Webshop.Application/Services/Customers/ICustomerService.cs
|
||||
using System.Threading.Tasks;
|
||||
using Webshop.Application.DTOs.Customers; // Korrektes Using für DTOs
|
||||
using Webshop.Application.DTOs; // CustomerDto
|
||||
using Webshop.Application.DTOs.Auth; // ChangePasswordRequestDto
|
||||
using Webshop.Application.DTOs.Customers; // UpdateCustomerProfileDto
|
||||
|
||||
namespace Webshop.Application.Services.Customers.Interfaces
|
||||
namespace Webshop.Application.Services.Customers
|
||||
{
|
||||
public interface ICustomerService
|
||||
{
|
||||
Task<CustomerDto?> GetMyProfileAsync(string userId);
|
||||
Task<bool> UpdateMyProfileAsync(string userId, UpdateCustomerProfileDto profileDto);
|
||||
Task<(bool Success, string ErrorMessage)> ChangePasswordAsync(string userId, ChangePasswordRequestDto request);
|
||||
Task<(bool Success, string ErrorMessage)> UpdateMyProfileAsync(string userId, UpdateCustomerProfileDto profileDto);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Webshop.Domain.Entities
|
||||
{
|
||||
public class ApplicationUser : IdentityUser
|
||||
{
|
||||
public DateTimeOffset CreatedDate { get; set; }
|
||||
public DateTimeOffset? LastActive { get; set; }
|
||||
public virtual Customer Customer { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,38 @@
|
||||
using System;
|
||||
|
||||
// src/Webshop.Domain/Entities/Customer.cs
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Collections.Generic;
|
||||
using Webshop.Domain.Identity; // Für ApplicationUser
|
||||
|
||||
namespace Webshop.Domain.Entities
|
||||
{
|
||||
public class Customer
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; }
|
||||
[Required]
|
||||
public string AspNetUserId { get; set; }
|
||||
[Required]
|
||||
[MaxLength(100)]
|
||||
public string FirstName { get; set; }
|
||||
[Required]
|
||||
[MaxLength(100)]
|
||||
public string LastName { get; set; }
|
||||
public Guid Id { get; set; } = Guid.NewGuid(); // Default-Wert setzen
|
||||
|
||||
public virtual ApplicationUser User { get; set; }
|
||||
[Required]
|
||||
public string AspNetUserId { get; set; } // Fremdschlüssel zu ApplicationUser.Id
|
||||
|
||||
[Required]
|
||||
[MaxLength(100)]
|
||||
public string FirstName { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
[MaxLength(100)]
|
||||
public string LastName { get; set; } = string.Empty;
|
||||
|
||||
// << ENTFERNT: Email ist auf ApplicationUser >>
|
||||
// << ENTFERNT: PhoneNumber ist auf ApplicationUser >>
|
||||
// << ENTFERNT: CreatedDate ist auf ApplicationUser >>
|
||||
|
||||
public Guid? DefaultShippingAddressId { get; set; } // Fremdschlüssel zur Standardversandadresse
|
||||
public Guid? DefaultBillingAddressId { get; set; } // Fremdschlüssel zur Standardrechnungsadresse
|
||||
|
||||
// Navigation Property zum ApplicationUser
|
||||
public virtual ApplicationUser User { get; set; } = default!; // Muss auf ApplicationUser verweisen
|
||||
|
||||
// Navigation Properties zu Collections
|
||||
public virtual ICollection<Address> Addresses { get; set; } = new List<Address>();
|
||||
public virtual ICollection<Order> Orders { get; set; } = new List<Order>();
|
||||
public virtual ICollection<Review> Reviews { get; set; } = new List<Review>();
|
||||
|
||||
16
Webshop.Domain/Identity/ApplicationUser.cs
Normal file
16
Webshop.Domain/Identity/ApplicationUser.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
// src/Webshop.Domain/Identity/ApplicationUser.cs
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System;
|
||||
|
||||
namespace Webshop.Domain.Identity // KORREKTER NAMESPACE
|
||||
{
|
||||
public class ApplicationUser : IdentityUser
|
||||
{
|
||||
public DateTimeOffset CreatedDate { get; set; } = DateTimeOffset.UtcNow; // Setzt Standardwert
|
||||
public DateTimeOffset? LastActive { get; set; }
|
||||
|
||||
// Navigation Property zur Customer-Entität (One-to-One)
|
||||
// Customer ist nullable, falls nicht jeder ApplicationUser ein Customer-Profil hat
|
||||
public virtual Entities.Customer? Customer { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
// src/Webshop.Domain/Interfaces/ICustomerRepository.cs
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Webshop.Domain.Entities;
|
||||
|
||||
@@ -6,7 +7,12 @@ namespace Webshop.Domain.Interfaces
|
||||
{
|
||||
public interface ICustomerRepository
|
||||
{
|
||||
Task<Customer?> GetByUserIdAsync(string userId);
|
||||
Task UpdateAsync(Customer customer);
|
||||
Task<IEnumerable<Customer>> GetAllAsync(); // Standard CRUD
|
||||
Task<Customer?> GetByIdAsync(Guid id); // Standard CRUD
|
||||
Task AddAsync(Customer entity); // Standard CRUD
|
||||
Task UpdateAsync(Customer entity); // Standard CRUD
|
||||
Task DeleteAsync(Guid id); // Standard CRUD
|
||||
|
||||
Task<Customer?> GetByUserIdAsync(string userId); // << DIESE METHODE IST NEU UND WICHTIG >>
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,15 @@
|
||||
// src/Webshop.Infrastructure/Repositories/CustomerRepository.cs
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Webshop.Domain.Entities;
|
||||
using Webshop.Domain.Interfaces;
|
||||
using Webshop.Infrastructure.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Webshop.Infrastructure.Repositories
|
||||
{
|
||||
public class CustomerRepository : ICustomerRepository
|
||||
public class CustomerRepository : ICustomerRepository // MUSS public sein
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
|
||||
@@ -16,15 +18,17 @@ namespace Webshop.Infrastructure.Repositories
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Customer?> GetByUserIdAsync(string userId)
|
||||
{
|
||||
return await _context.Customers.FirstOrDefaultAsync(c => c.AspNetUserId == userId);
|
||||
}
|
||||
// Beispiel-Implementierungen (wenn nicht schon vorhanden):
|
||||
public async Task<IEnumerable<Customer>> GetAllAsync() => await _context.Customers.ToListAsync();
|
||||
public async Task<Customer?> GetByIdAsync(Guid id) => await _context.Customers.FindAsync(id);
|
||||
public async Task AddAsync(Customer entity) { _context.Customers.Add(entity); await _context.SaveChangesAsync(); }
|
||||
public async Task UpdateAsync(Customer entity) { _context.Customers.Update(entity); await _context.SaveChangesAsync(); }
|
||||
public async Task DeleteAsync(Guid id) { var entity = await _context.Customers.FindAsync(id); if (entity != null) { _context.Customers.Remove(entity); await _context.SaveChangesAsync(); } }
|
||||
|
||||
public async Task UpdateAsync(Customer customer)
|
||||
// KORREKTE IMPLEMENTIERUNG F<>R GetByUserIdAsync
|
||||
public async Task<Customer?> GetByUserIdAsync(string aspNetUserId)
|
||||
{
|
||||
_context.Customers.Update(customer);
|
||||
await _context.SaveChangesAsync();
|
||||
return await _context.Customers.FirstOrDefaultAsync(c => c.AspNetUserId == aspNetUserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,15 @@
|
||||
// src/Webshop.Infrastructure/Repositories/SupplierRepository.cs
|
||||
// Auto-generiert von CreateWebshopFiles.ps1 (aktualisiert um Implementierungen)
|
||||
using Microsoft.EntityFrameworkCore; // Wichtig für ToListAsync, FindAsync etc.
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Webshop.Domain.Entities;
|
||||
using Webshop.Domain.Interfaces;
|
||||
using Webshop.Infrastructure.Data;
|
||||
using System; // Für Guid
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Webshop.Infrastructure.Repositories
|
||||
{
|
||||
public class SupplierRepository : ISupplierRepository // Hier muss das Interface stehen
|
||||
public class SupplierRepository : ISupplierRepository // MUSS public sein
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
|
||||
@@ -19,8 +18,6 @@ namespace Webshop.Infrastructure.Repositories
|
||||
_context = context;
|
||||
}
|
||||
|
||||
// --- IMPLEMENTIERUNG DER ISupplierRepository METHODEN ---
|
||||
|
||||
public async Task<IEnumerable<Supplier>> GetAllSuppliersAsync()
|
||||
{
|
||||
return await _context.Suppliers.ToListAsync();
|
||||
@@ -34,7 +31,7 @@ namespace Webshop.Infrastructure.Repositories
|
||||
public async Task AddSupplierAsync(Supplier supplier)
|
||||
{
|
||||
_context.Suppliers.Add(supplier);
|
||||
await _context.SaveChangesAsync(); // Änderungen in der DB speichern
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateSupplierAsync(Supplier supplier)
|
||||
@@ -45,11 +42,11 @@ namespace Webshop.Infrastructure.Repositories
|
||||
|
||||
public async Task DeleteSupplierAsync(Guid id)
|
||||
{
|
||||
var supplier = await _context.Suppliers.FindAsync(id); // Lieferant zuerst finden
|
||||
var supplier = await _context.Suppliers.FindAsync(id);
|
||||
if (supplier != null)
|
||||
{
|
||||
_context.Suppliers.Remove(supplier); // Lieferant entfernen
|
||||
await _context.SaveChangesAsync(); // Änderungen speichern
|
||||
_context.Suppliers.Remove(supplier);
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user