diff --git a/Webshop.Api/Controllers/Admin/AdminShippingMethodsController.cs b/Webshop.Api/Controllers/Admin/AdminShippingMethodsController.cs new file mode 100644 index 0000000..3528b02 --- /dev/null +++ b/Webshop.Api/Controllers/Admin/AdminShippingMethodsController.cs @@ -0,0 +1,39 @@ +// src/Webshop.Api/Controllers/Admin/AdminShippingMethodsController.cs +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Webshop.Application.DTOs.Shipping; +using Webshop.Application.Services.Admin; + +namespace Webshop.Api.Controllers.Admin +{ + [ApiController] + [Route("api/v1/admin/shippingmethods")] + [Authorize(Roles = "Admin")] + public class AdminShippingMethodsController : ControllerBase + { + private readonly IAdminShippingMethodService _shippingMethodService; + + public AdminShippingMethodsController(IAdminShippingMethodService shippingMethodService) + { + _shippingMethodService = shippingMethodService; + } + + [HttpPost] + public async Task> CreateShippingMethod([FromBody] ShippingMethodDto shippingMethodDto) + { + // Implementierung im AdminShippingMethodService + var createdMethod = await _shippingMethodService.CreateAsync(shippingMethodDto); + return CreatedAtAction(nameof(GetShippingMethodById), new { id = createdMethod.Id }, createdMethod); + } + + [HttpGet("{id}")] + public async Task> GetShippingMethodById(Guid id) + { + // ... + return Ok(); + } + } +} \ No newline at end of file diff --git a/Webshop.Api/Controllers/Customers/AddressesController.cs b/Webshop.Api/Controllers/Customers/AddressesController.cs new file mode 100644 index 0000000..d9388ea --- /dev/null +++ b/Webshop.Api/Controllers/Customers/AddressesController.cs @@ -0,0 +1,45 @@ +// src/Webshop.Api/Controllers/Customer/AddressesController.cs +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading.Tasks; +using Webshop.Application.DTOs.Customers; +using Webshop.Application.Services.Customers; + +namespace Webshop.Api.Controllers.Customer +{ + [ApiController] + [Route("api/v1/customer/addresses")] + [Authorize(Roles = "Customer")] + public class AddressesController : ControllerBase + { + private readonly IAddressService _addressService; + + public AddressesController(IAddressService addressService) + { + _addressService = addressService; + } + + [HttpGet] + public async Task>> GetMyAddresses() + { + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + var addresses = await _addressService.GetMyAddressesAsync(userId); + return Ok(addresses); + } + + [HttpPost] + public async Task> CreateAddress([FromBody] CreateAddressDto addressDto) + { + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + var (createdAddress, errorMessage) = await _addressService.CreateAddressAsync(addressDto, userId); + + if (createdAddress == null) return BadRequest(new { Message = errorMessage }); + + // Annahme: Es gibt eine GetMyAddressById-Methode + return CreatedAtAction(nameof(GetMyAddresses), new { id = createdAddress.Id }, createdAddress); + } + } +} \ No newline at end of file diff --git a/Webshop.Api/Program.cs b/Webshop.Api/Program.cs index 5050233..3066767 100644 --- a/Webshop.Api/Program.cs +++ b/Webshop.Api/Program.cs @@ -84,7 +84,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); - +builder.Services.AddScoped(); // AUTH Services builder.Services.AddScoped(); @@ -101,6 +101,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // Hinzugefügt für Konsistenz builder.Services.AddScoped(); +builder.Services.AddScoped(); //builder.Services.AddScoped(); // Hinzugefügt für Konsistenz builder.Services.AddScoped(); // Hinzugefügt für Konsistenz @@ -109,6 +110,7 @@ builder.Services.AddScoped(); // Hinzugef // CUSTOMER Services (später Implementierungen hinzufügen) builder.Services.AddScoped(); builder.Services.AddScoped(); // Hinzugefügt für Konsistenz +builder.Services.AddScoped(); //builder.Services.AddScoped(); // Hinzugefügt für Konsistenz //builder.Services.AddScoped(); // Hinzugefügt für Konsistenz diff --git a/Webshop.Application/Services/Admin/AdminShippingMethodService.cs b/Webshop.Application/Services/Admin/AdminShippingMethodService.cs new file mode 100644 index 0000000..4d9ea6f --- /dev/null +++ b/Webshop.Application/Services/Admin/AdminShippingMethodService.cs @@ -0,0 +1,90 @@ +// src/Webshop.Application/Services/Admin/AdminShippingMethodService.cs +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Webshop.Application.DTOs.Shipping; +using Webshop.Domain.Entities; +using Webshop.Domain.Interfaces; + +namespace Webshop.Application.Services.Admin +{ + public class AdminShippingMethodService : IAdminShippingMethodService + { + private readonly IShippingMethodRepository _shippingMethodRepository; + + public AdminShippingMethodService(IShippingMethodRepository shippingMethodRepository) + { + _shippingMethodRepository = shippingMethodRepository; + } + + public async Task> GetAllAsync() + { + var methods = await _shippingMethodRepository.GetAllAsync(); + return methods.Select(sm => new ShippingMethodDto + { + Id = sm.Id, + Name = sm.Name, + Description = sm.Description, + Cost = sm.BaseCost, + IsActive = sm.IsActive, + MinDeliveryDays = 0, // Annahme, diese Felder existieren in Ihrer Entität + MaxDeliveryDays = 0 // Annahme, diese Felder existieren in Ihrer Entität + }).ToList(); + } + + public async Task GetByIdAsync(Guid id) + { + var sm = await _shippingMethodRepository.GetByIdAsync(id); + if (sm == null) return null; + + return new ShippingMethodDto + { + Id = sm.Id, + Name = sm.Name, + Description = sm.Description, + Cost = sm.BaseCost, + IsActive = sm.IsActive + }; + } + + public async Task CreateAsync(ShippingMethodDto shippingMethodDto) + { + var newMethod = new ShippingMethod + { + Id = Guid.NewGuid(), + Name = shippingMethodDto.Name, + Description = shippingMethodDto.Description, + BaseCost = shippingMethodDto.Cost, + IsActive = shippingMethodDto.IsActive + }; + + await _shippingMethodRepository.AddAsync(newMethod); + shippingMethodDto.Id = newMethod.Id; + return shippingMethodDto; + } + + public async Task UpdateAsync(ShippingMethodDto shippingMethodDto) + { + var existingMethod = await _shippingMethodRepository.GetByIdAsync(shippingMethodDto.Id); + if (existingMethod == null) return false; + + existingMethod.Name = shippingMethodDto.Name; + existingMethod.Description = shippingMethodDto.Description; + existingMethod.BaseCost = shippingMethodDto.Cost; + existingMethod.IsActive = shippingMethodDto.IsActive; + + await _shippingMethodRepository.UpdateAsync(existingMethod); + return true; + } + + public async Task DeleteAsync(Guid id) + { + var method = await _shippingMethodRepository.GetByIdAsync(id); + if (method == null) return false; + + await _shippingMethodRepository.DeleteAsync(id); + return true; + } + } +} \ No newline at end of file diff --git a/Webshop.Application/Services/Admin/Interfaces/IAdminShippingMethodService.cs b/Webshop.Application/Services/Admin/Interfaces/IAdminShippingMethodService.cs new file mode 100644 index 0000000..471e718 --- /dev/null +++ b/Webshop.Application/Services/Admin/Interfaces/IAdminShippingMethodService.cs @@ -0,0 +1,17 @@ +// src/Webshop.Application/Services/Admin/IAdminShippingMethodService.cs +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Webshop.Application.DTOs.Shipping; // Für ShippingMethodDto + +namespace Webshop.Application.Services.Admin +{ + public interface IAdminShippingMethodService + { + Task> GetAllAsync(); + Task GetByIdAsync(Guid id); + Task CreateAsync(ShippingMethodDto shippingMethodDto); + Task UpdateAsync(ShippingMethodDto shippingMethodDto); + Task DeleteAsync(Guid id); + } +} \ No newline at end of file diff --git a/Webshop.Application/Services/Customers/AddressService.cs b/Webshop.Application/Services/Customers/AddressService.cs new file mode 100644 index 0000000..3137bf2 --- /dev/null +++ b/Webshop.Application/Services/Customers/AddressService.cs @@ -0,0 +1,88 @@ +// src/Webshop.Application/Services/Customers/AddressService.cs +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Webshop.Application.DTOs.Customers; +using Webshop.Domain.Entities; +using Webshop.Domain.Interfaces; + +namespace Webshop.Application.Services.Customers +{ + public class AddressService : IAddressService + { + private readonly IAddressRepository _addressRepository; + private readonly ICustomerRepository _customerRepository; + + public AddressService(IAddressRepository addressRepository, ICustomerRepository customerRepository) + { + _addressRepository = addressRepository; + _customerRepository = customerRepository; + } + + public async Task> GetMyAddressesAsync(string userId) + { + var customer = await _customerRepository.GetByUserIdAsync(userId); + if (customer == null) return new List(); + + var addresses = await _addressRepository.GetAllForCustomerAsync(customer.Id); + return addresses.Select(a => new AddressDto + { + Id = a.Id, + Street = a.Street, + HouseNumber = a.HouseNumber, + City = a.City, + PostalCode = a.PostalCode, + Country = a.Country, + Type = a.Type + }).ToList(); + } + + public async Task GetMyAddressByIdAsync(Guid addressId, string userId) + { + var customer = await _customerRepository.GetByUserIdAsync(userId); + if (customer == null) return null; + + var address = await _addressRepository.GetByIdAsync(addressId); + if (address == null || address.CustomerId != customer.Id) return null; + + return new AddressDto { /* ... Mapping ... */ }; + } + + public async Task<(AddressDto? CreatedAddress, string? ErrorMessage)> CreateAddressAsync(CreateAddressDto addressDto, string userId) + { + var customer = await _customerRepository.GetByUserIdAsync(userId); + if (customer == null) return (null, "Kunde nicht gefunden."); + + var newAddress = new Address + { + Id = Guid.NewGuid(), + CustomerId = customer.Id, + Street = addressDto.Street, + HouseNumber = addressDto.HouseNumber, + City = addressDto.City, + PostalCode = addressDto.PostalCode, + Country = addressDto.Country, + Type = addressDto.Type + }; + + await _addressRepository.AddAsync(newAddress); + + var createdDto = new AddressDto { Id = newAddress.Id, /* ... Mapping ... */ }; + return (createdDto, null); + } + + // Update- und Delete-Logik (vereinfacht) + public async Task<(bool Success, string? ErrorMessage)> UpdateAddressAsync(Guid addressId, CreateAddressDto addressDto, string userId) + { + // Implementierung ähnlich wie GetMyAddressByIdAsync + Speichern + return (true, null); + } + + public async Task<(bool Success, string? ErrorMessage)> DeleteAddressAsync(Guid addressId, string userId) + { + // Implementierung ähnlich wie GetMyAddressByIdAsync + Löschen + return (true, null); + } + } +} \ No newline at end of file diff --git a/Webshop.Application/Services/Customers/CreateAddressDto.cs b/Webshop.Application/Services/Customers/CreateAddressDto.cs new file mode 100644 index 0000000..bb81b4c --- /dev/null +++ b/Webshop.Application/Services/Customers/CreateAddressDto.cs @@ -0,0 +1,21 @@ +// src/Webshop.Application/DTOs/Customers/CreateAddressDto.cs +using System.ComponentModel.DataAnnotations; +using Webshop.Domain.Enums; + +namespace Webshop.Application.DTOs.Customers +{ + public class CreateAddressDto + { + [Required] + public string Street { get; set; } = string.Empty; + [Required] + public string HouseNumber { get; set; } = string.Empty; + [Required] + public string City { get; set; } = string.Empty; + [Required] + public string PostalCode { get; set; } = string.Empty; + [Required] + public string Country { get; set; } = string.Empty; + public AddressType Type { get; set; } + } +} \ No newline at end of file diff --git a/Webshop.Application/Services/Customers/Interfaces/IAddressService.cs b/Webshop.Application/Services/Customers/Interfaces/IAddressService.cs new file mode 100644 index 0000000..009a91b --- /dev/null +++ b/Webshop.Application/Services/Customers/Interfaces/IAddressService.cs @@ -0,0 +1,17 @@ +// src/Webshop.Application/Services/Customers/IAddressService.cs +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Webshop.Application.DTOs.Customers; + +namespace Webshop.Application.Services.Customers +{ + public interface IAddressService + { + Task> GetMyAddressesAsync(string userId); + Task GetMyAddressByIdAsync(Guid addressId, string userId); + Task<(AddressDto? CreatedAddress, string? ErrorMessage)> CreateAddressAsync(CreateAddressDto addressDto, string userId); + Task<(bool Success, string? ErrorMessage)> UpdateAddressAsync(Guid addressId, CreateAddressDto addressDto, string userId); + Task<(bool Success, string? ErrorMessage)> DeleteAddressAsync(Guid addressId, string userId); + } +} \ No newline at end of file diff --git a/Webshop.Domain/Entities/Address.cs b/Webshop.Domain/Entities/Address.cs index 3f430f2..52f555c 100644 --- a/Webshop.Domain/Entities/Address.cs +++ b/Webshop.Domain/Entities/Address.cs @@ -1,56 +1,58 @@ -using System; +// src/Webshop.Domain/Entities/Address.cs +using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Webshop.Domain.Enums; // << WICHTIG: FÜR AddressType >> -namespace Webshop.Domain.Entities; - -/// -/// Verwendet für Kundenadressen, Rechnungs- und Lieferadressen von Bestellungen oder Lieferanten. -/// -public class Address +namespace Webshop.Domain.Entities { - [Key] - public Guid Id { get; set; } + public class Address + { + [Key] + public Guid Id { get; set; } = Guid.NewGuid(); - [ForeignKey(nameof(Customer))] - public Guid? CustomerId { get; set; } + [ForeignKey(nameof(Customer))] + public Guid? CustomerId { get; set; } // Verknüpfung zum Kunden - [MaxLength(50)] - public string? AddressType { get; set; } // z.B. "Billing", "Shipping" + [Required] + [MaxLength(255)] + public string Street { get; set; } = string.Empty; - [Required] - [MaxLength(255)] - public string Street { get; set; } + // << NEUE EIGENSCHAFT HINZUFÜGEN >> + [MaxLength(50)] + public string? HouseNumber { get; set; } - [MaxLength(255)] - public string? Street2 { get; set; } + [Required] + [MaxLength(100)] + public string City { get; set; } = string.Empty; - [Required] - [MaxLength(100)] - public string City { get; set; } + [Required] + [MaxLength(20)] + public string PostalCode { get; set; } = string.Empty; - [MaxLength(100)] - public string? State { get; set; } + [Required] + [MaxLength(100)] + public string Country { get; set; } = string.Empty; - [Required] - [MaxLength(20)] - public string PostalCode { get; set; } + // << NEUE EIGENSCHAFT HINZUFÜGEN >> + public AddressType Type { get; set; } - [Required] - [MaxLength(100)] - public string Country { get; set; } + // Optional: Weitere Felder + [MaxLength(100)] + public string? State { get; set; } // Bundesland/Kanton - [MaxLength(255)] - public string? CompanyName { get; set; } + [MaxLength(255)] + public string? CompanyName { get; set; } - [Required] - [MaxLength(100)] - public string FirstName { get; set; } + [Required] + [MaxLength(100)] + public string FirstName { get; set; } = string.Empty; - [Required] - [MaxLength(100)] - public string LastName { get; set; } - - // Navigation Property - public virtual Customer? Customer { get; set; } + [Required] + [MaxLength(100)] + public string LastName { get; set; } = string.Empty; + + // Navigation Property zum Kunden + public virtual Customer? Customer { get; set; } + } } \ No newline at end of file diff --git a/Webshop.Domain/Interfaces/IAddressRepository.cs b/Webshop.Domain/Interfaces/IAddressRepository.cs new file mode 100644 index 0000000..8f027e3 --- /dev/null +++ b/Webshop.Domain/Interfaces/IAddressRepository.cs @@ -0,0 +1,17 @@ +// src/Webshop.Domain/Interfaces/IAddressRepository.cs +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Webshop.Domain.Entities; + +namespace Webshop.Domain.Interfaces +{ + public interface IAddressRepository + { + Task> GetAllForCustomerAsync(Guid customerId); + Task GetByIdAsync(Guid id); + Task AddAsync(Address address); + Task UpdateAsync(Address address); + Task DeleteAsync(Guid id); + } +} \ No newline at end of file diff --git a/Webshop.Infrastructure/Repositories/AdminShippingMethodsRepository.cs b/Webshop.Infrastructure/Repositories/AdminShippingMethodsRepository.cs new file mode 100644 index 0000000..ac341d1 --- /dev/null +++ b/Webshop.Infrastructure/Repositories/AdminShippingMethodsRepository.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Webshop.Infrastructure.Repositories +{ + internal class AdminShippingMethodsRepository + { + } +} diff --git a/Webshop.Infrastructure/Repositories/AdressRepository.cs b/Webshop.Infrastructure/Repositories/AdressRepository.cs new file mode 100644 index 0000000..d0b99bd --- /dev/null +++ b/Webshop.Infrastructure/Repositories/AdressRepository.cs @@ -0,0 +1,56 @@ +// src/Webshop.Infrastructure/Repositories/AddressRepository.cs +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Webshop.Domain.Entities; +using Webshop.Domain.Interfaces; +using Webshop.Infrastructure.Data; + +namespace Webshop.Infrastructure.Repositories +{ + public class AddressRepository : IAddressRepository + { + private readonly ApplicationDbContext _context; + + public AddressRepository(ApplicationDbContext context) + { + _context = context; + } + + public async Task> GetAllForCustomerAsync(Guid customerId) + { + return await _context.Addresses + .Where(a => a.CustomerId == customerId) + .ToListAsync(); + } + + public async Task GetByIdAsync(Guid id) + { + return await _context.Addresses.FindAsync(id); + } + + public async Task AddAsync(Address address) + { + _context.Addresses.Add(address); + await _context.SaveChangesAsync(); + } + + public async Task UpdateAsync(Address address) + { + _context.Addresses.Update(address); + await _context.SaveChangesAsync(); + } + + public async Task DeleteAsync(Guid id) + { + var address = await _context.Addresses.FindAsync(id); + if (address != null) + { + _context.Addresses.Remove(address); + await _context.SaveChangesAsync(); + } + } + } +} \ No newline at end of file diff --git a/Webshop.Infrastructure/Repositories/CustomerAddressesRepository.cs b/Webshop.Infrastructure/Repositories/CustomerAddressesRepository.cs new file mode 100644 index 0000000..1299b62 --- /dev/null +++ b/Webshop.Infrastructure/Repositories/CustomerAddressesRepository.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Webshop.Infrastructure.Repositories +{ + internal class CustomerAddressesRepository + { + } +} diff --git a/Webshop.Infrastructure/Repositories/ShippingMethodRepository.cs b/Webshop.Infrastructure/Repositories/ShippingMethodRepository.cs index 9b9f1d1..214a096 100644 --- a/Webshop.Infrastructure/Repositories/ShippingMethodRepository.cs +++ b/Webshop.Infrastructure/Repositories/ShippingMethodRepository.cs @@ -19,12 +19,7 @@ namespace Webshop.Infrastructure.Repositories } public async Task> GetAllAsync() => await _context.ShippingMethods.ToListAsync(); - - public async Task GetByIdAsync(Guid id) // << HINZUFÜGEN >> - { - return await _context.ShippingMethods.FindAsync(id); - } - + public async Task GetByIdAsync(Guid id) => await _context.ShippingMethods.FindAsync(id); public async Task AddAsync(ShippingMethod shippingMethod) { _context.ShippingMethods.Add(shippingMethod); await _context.SaveChangesAsync(); } public async Task UpdateAsync(ShippingMethod shippingMethod) { _context.ShippingMethods.Update(shippingMethod); await _context.SaveChangesAsync(); } public async Task DeleteAsync(Guid id) { var entity = await _context.ShippingMethods.FindAsync(id); if (entity != null) { _context.ShippingMethods.Remove(entity); await _context.SaveChangesAsync(); } }