example values und aufräumen

This commit is contained in:
Tizian.Breuch
2025-08-01 09:55:35 +02:00
parent f4c56c7648
commit c8f97ef748
3 changed files with 145 additions and 318 deletions

View File

@@ -1,45 +1,47 @@
// --- Core Frameworks & Libraries ---
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.HttpOverrides; // For UseForwardedHeaders using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; // For ILogger
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models; // For Swagger OpenAPI models using Microsoft.OpenApi.Models;
using Resend; using Resend;
using System.Text; using System.Text;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Webshop.Api.SwaggerFilters; // For AuthorizeOperationFilter
using Webshop.Application.Services.Admin; // AdminUserService, AdminProductService // --- Eigene Namespaces ---
using Webshop.Api.SwaggerFilters;
using Webshop.Application.Services.Admin;
using Webshop.Application.Services.Admin.Interfaces; using Webshop.Application.Services.Admin.Interfaces;
using Webshop.Application.Services.Auth; // IAuthService, AuthService using Webshop.Application.Services.Auth;
using Webshop.Application.Services.Customers; using Webshop.Application.Services.Customers;
using Webshop.Application.Services.Customers.Interfaces; using Webshop.Application.Services.Customers.Interfaces;
using Webshop.Application.Services.Public; // ProductService using Webshop.Application.Services.Public;
using Webshop.Application.Services.Public.Interfaces; using Webshop.Application.Services.Public.Interfaces;
using Webshop.Domain.Entities; using Webshop.Domain.Entities;
using Webshop.Domain.Identity; using Webshop.Domain.Identity;
using Webshop.Domain.Interfaces; // IProductRepository using Webshop.Domain.Interfaces;
using Webshop.Infrastructure.Data; // ApplicationDbContext using Webshop.Infrastructure.Data;
using Webshop.Infrastructure.Repositories; // ProductRepository using Webshop.Infrastructure.Repositories;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// --- START: DIENSTE ZUM CONTAINER HINZUF<55>GEN --- // --- 1. Dependency Injection Konfiguration ---
// 1. Datenbank-Kontext (DbContext) registrieren // Datenbank-Kontext
builder.Services.AddDbContext<ApplicationDbContext>(options => builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")) options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))
); );
// 2. ASP.NET Core Identity f<EFBFBD>r Benutzerverwaltung registrieren // ASP.NET Core Identity mit ApplicationUser
builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options => builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{ {
options.SignIn.RequireConfirmedAccount = true; options.SignIn.RequireConfirmedEmail = true;
}) })
.AddEntityFrameworkStores<ApplicationDbContext>() // Stellen Sie sicher, dass Ihr DbContext-Name hier korrekt ist .AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders(); .AddDefaultTokenProviders();
// Optional: Passe die Anforderungen f<>r Passw<EFBFBD>rter f<>r die Entwicklung an // Passwort-Anforderungen f<>r die Entwicklung lockern
builder.Services.Configure<IdentityOptions>(options => builder.Services.Configure<IdentityOptions>(options =>
{ {
options.Password.RequireDigit = false; options.Password.RequireDigit = false;
@@ -47,14 +49,11 @@ builder.Services.Configure<IdentityOptions>(options =>
options.Password.RequireNonAlphanumeric = false; options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false; options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false; options.Password.RequireLowercase = false;
options.SignIn.RequireConfirmedEmail = true; // F<>r einfache Entwicklung/Tests
}); });
// JWT-Authentifizierung
// 3. JWT-Authentifizierung konfigurieren
var jwtSettings = builder.Configuration.GetSection("JwtSettings"); var jwtSettings = builder.Configuration.GetSection("JwtSettings");
var secretKey = jwtSettings["Secret"] ?? throw new InvalidOperationException("JWT Secret not found in configuration."); var secretKey = jwtSettings["Secret"] ?? throw new InvalidOperationException("JWT Secret not found in configuration.");
builder.Services.AddAuthentication(options => builder.Services.AddAuthentication(options =>
{ {
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
@@ -73,9 +72,8 @@ builder.Services.AddAuthentication(options =>
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)) IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey))
}; };
}); });
builder.Services.AddAuthorization(); // Aktiviert die Autorisierung builder.Services.AddAuthorization();
// 4. Unsere eigenen Interfaces und Klassen registrieren (Dependency Injection)
// Repositories // Repositories
builder.Services.AddScoped<IProductRepository, ProductRepository>(); builder.Services.AddScoped<IProductRepository, ProductRepository>();
builder.Services.AddScoped<ISupplierRepository, SupplierRepository>(); builder.Services.AddScoped<ISupplierRepository, SupplierRepository>();
@@ -85,114 +83,94 @@ builder.Services.AddScoped<ICategoryRepository, CategoryRepository>();
builder.Services.AddScoped<IOrderRepository, OrderRepository>(); builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.AddScoped<IShippingMethodRepository, ShippingMethodRepository>(); builder.Services.AddScoped<IShippingMethodRepository, ShippingMethodRepository>();
builder.Services.AddScoped<IAddressRepository, AddressRepository>(); builder.Services.AddScoped<IAddressRepository, AddressRepository>();
// AUTH Services builder.Services.AddScoped<IDiscountRepository, DiscountRepository>();
builder.Services.AddScoped<IAuthService, AuthService>(); builder.Services.AddScoped<IReviewRepository, ReviewRepository>();
builder.Services.AddScoped<ISettingRepository, SettingRepository>();
// PUBLIC Services // Services
builder.Services.AddScoped<IAuthService, AuthService>();
builder.Services.AddScoped<IProductService, ProductService>(); builder.Services.AddScoped<IProductService, ProductService>();
builder.Services.AddScoped<IPaymentMethodService, PaymentMethodService>(); builder.Services.AddScoped<IPaymentMethodService, PaymentMethodService>();
builder.Services.AddScoped<ICategoryService, CategoryService>(); builder.Services.AddScoped<ICategoryService, CategoryService>();
builder.Services.AddScoped<ICategoryService, CategoryService>();
// ADMIN Services
builder.Services.AddScoped<IAdminUserService, AdminUserService>(); builder.Services.AddScoped<IAdminUserService, AdminUserService>();
builder.Services.AddScoped<IAdminProductService, AdminProductService>(); builder.Services.AddScoped<IAdminProductService, AdminProductService>();
builder.Services.AddScoped<IAdminSupplierService, AdminSupplierService>(); builder.Services.AddScoped<IAdminSupplierService, AdminSupplierService>();
builder.Services.AddScoped<IAdminPaymentMethodService, AdminPaymentMethodService>(); builder.Services.AddScoped<IAdminPaymentMethodService, AdminPaymentMethodService>();
builder.Services.AddScoped<IAdminCategoryService, AdminCategoryService>(); // Hinzugef<65>gt f<>r Konsistenz builder.Services.AddScoped<IAdminCategoryService, AdminCategoryService>();
builder.Services.AddScoped<IAdminOrderService, AdminOrderService>(); builder.Services.AddScoped<IAdminOrderService, AdminOrderService>();
builder.Services.AddScoped<IAdminShippingMethodService, AdminShippingMethodService>(); builder.Services.AddScoped<IAdminShippingMethodService, AdminShippingMethodService>();
builder.Services.AddScoped<IAdminDiscountService, AdminDiscountService>();
//builder.Services.AddScoped<IAdminDiscountService, AdminDiscountService>(); // Hinzugef<65>gt f<>r Konsistenz builder.Services.AddScoped<IAdminSettingService, AdminSettingService>();
builder.Services.AddScoped<IAdminOrderService, AdminOrderService>(); // Hinzugef<65>gt f<>r Konsistenz
//builder.Services.AddScoped<IAdminSettingService, AdminSettingService>(); // Hinzugef<65>gt f<>r Konsistenz
// CUSTOMER Services (sp<73>ter Implementierungen hinzuf<75>gen)
builder.Services.AddScoped<ICustomerService, CustomerService>(); builder.Services.AddScoped<ICustomerService, CustomerService>();
builder.Services.AddScoped<IOrderService, OrderService>(); // Hinzugef<65>gt f<>r Konsistenz builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddScoped<IAddressService, AddressService>(); builder.Services.AddScoped<IAddressService, AddressService>();
//builder.Services.AddScoped<ICheckoutService, CheckoutService>(); // Hinzugef<65>gt f<>r Konsistenz builder.Services.AddScoped<ICheckoutService, CheckoutService>();
//builder.Services.AddScoped<IReviewService, ReviewService>(); // Hinzugef<65>gt f<>r Konsistenz builder.Services.AddScoped<IReviewService, ReviewService>();
// --- NEU: Resend E-Mail-Dienst konfigurieren --- // Externe Dienste (Resend)
builder.Services.AddOptions(); // Stellt sicher, dass Options konfiguriert werden k<>nnen builder.Services.AddHttpClient<ResendClient>();
builder.Services.AddHttpClient<ResendClient>(); // F<>gt HttpClient f<>r Resend hinzu
builder.Services.Configure<ResendClientOptions>(options => builder.Services.Configure<ResendClientOptions>(options =>
{ {
// Der API-Token kommt aus den Konfigurationen (z.B. appsettings.json oder Umgebungsvariablen) options.ApiToken = builder.Configuration["Resend:ApiToken"]!;
options.ApiToken = builder.Configuration["Resend:ApiToken"]!; // << ANPASSEN >>
}); });
builder.Services.AddTransient<IResend, ResendClient>(); builder.Services.AddTransient<IResend, ResendClient>();
// Controller und API-Infrastruktur
// 5. Controller und Swagger/OpenAPI hinzuf<75>gen
builder.Services.AddControllers() builder.Services.AddControllers()
.AddJsonOptions(options => .AddJsonOptions(options =>
{ {
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
}); });
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
// Swagger / OpenAPI Konfiguration
builder.Services.AddSwaggerGen(c => builder.Services.AddSwaggerGen(c =>
{ {
// 1. JWT Security Definition hinzuf<75>gen c.TagActionsBy(api =>
{
if (api.RelativePath.StartsWith("api/v1/admin")) return new[] { "Admin" };
if (api.RelativePath.StartsWith("api/v1/auth")) return new[] { "Auth" };
if (api.RelativePath.StartsWith("api/v1/customer")) return new[] { "Customer" };
if (api.RelativePath.StartsWith("api/v1/public")) return new[] { "Public" };
return new[] { "Default" };
});
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{ {
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", Description = "JWT Authorization header. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization", Name = "Authorization",
In = ParameterLocation.Header, // Der Token wird im Header gesendet In = ParameterLocation.Header,
Type = SecuritySchemeType.Http, // Dies ist ein HTTP-Schema Type = SecuritySchemeType.Http,
Scheme = "Bearer" // Das Schema ist "Bearer" Scheme = "Bearer"
}); });
// 2. Security Requirement f<>r alle Operationen hinzuf<75>gen
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer" // Verweist auf die oben definierte "Bearer" Sicherheit
}
},
new string[] {} // Keine spezifischen "Scopes" f<>r JWT (leer lassen)
}
});
c.OperationFilter<AuthorizeOperationFilter>(); c.OperationFilter<AuthorizeOperationFilter>();
c.SchemaFilter<AddExampleSchemaFilter>();
c.OperationFilter<LoginExampleOperationFilter>(); c.OperationFilter<LoginExampleOperationFilter>();
c.OperationFilter<PaymentMethodExampleOperationFilter>(); c.OperationFilter<PaymentMethodExampleOperationFilter>();
c.OperationFilter<SupplierExampleOperationFilter>(); c.OperationFilter<SupplierExampleOperationFilter>();
c.OperationFilter<ShippingMethodExampleOperationFilter>();
c.SchemaFilter<AddExampleSchemaFilter>();
}); });
// --- ENDE: DIENSTE ZUM CONTAINER HINZUF<55>GEN ---
var app = builder.Build(); // <-- Hier wird die App gebaut // --- 2. HTTP Request Pipeline Konfiguration ---
// OPTIONALE BL<42>CKE F<>R MIGRATION UND BENUTZERINITIALISIERUNG - DIESER CODE WIRD VOR APP.RUN() AUSGEF<45>HRT var app = builder.Build();
// OPTIONALE BL<42>CKE F<>R MIGRATION UND BENUTZERINITIALISIERUNG - DIESER CODE WIRD VOR APP.RUN() AUSGEF<45>HRT
// F<>hre Datenbank-Migrationen und Initialisierungslogik beim Start aus
using (var scope = app.Services.CreateScope()) using (var scope = app.Services.CreateScope())
{ {
var services = scope.ServiceProvider; var services = scope.ServiceProvider;
try try
{ {
var context = services.GetRequiredService<ApplicationDbContext>(); var context = services.GetRequiredService<ApplicationDbContext>();
// Wendet ausstehende Datenbank-Migrationen an (sehr n<>tzlich f<>r Entwicklung/Tests)
context.Database.Migrate(); context.Database.Migrate();
// --- TEMPOR<4F>RER INITIALER ADMIN- UND KUNDEN-SETUP (NUR F<>R ERSTE ENTWICKLUNG!) --- // TEMPOR<4F>RER INITIALER ADMIN- UND KUNDEN-SETUP
// Dieser Block erstellt Rollen und initiale Benutzer, falls sie noch nicht existieren. // HINWEIS: Dieser Block sollte in der Produktion entfernt oder deaktiviert werden.
// BITTE ENTFERNEN ODER KOMMENTIEREN SIE DIESEN BLOCK AUS, NACHDEM SIE IHRE ERSTEN BENUTZER ERSTELLT HABEN!
var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>(); var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>();
var userManager = services.GetRequiredService<UserManager<ApplicationUser>>(); // << KORREKT: UserManager f<>r ApplicationUser >> var userManager = services.GetRequiredService<UserManager<ApplicationUser>>();
string[] roleNames = { "Admin", "Customer" }; string[] roleNames = { "Admin", "Customer" };
foreach (var roleName in roleNames) foreach (var roleName in roleNames)
{ {
if (!await roleManager.RoleExistsAsync(roleName)) if (!await roleManager.RoleExistsAsync(roleName))
@@ -201,102 +179,66 @@ using (var scope = app.Services.CreateScope())
} }
} }
// Erstelle einen initialen Admin-Benutzer und sein Customer-Profil var adminUser = await userManager.FindByEmailAsync("admin@yourwebshop.com");
var adminUser = await userManager.FindByEmailAsync("admin@yourwebshop.com"); // << ANPASSEN >>
if (adminUser == null) if (adminUser == null)
{ {
adminUser = new ApplicationUser // << KORREKT: ERSTELLT ApplicationUser >> adminUser = new ApplicationUser { UserName = "admin@yourwebshop.com", Email = "admin@yourwebshop.com", EmailConfirmed = true, CreatedDate = DateTimeOffset.UtcNow, LastActive = DateTimeOffset.UtcNow };
{ var createAdmin = await userManager.CreateAsync(adminUser, "SecureAdminPass123!");
UserName = "admin@yourwebshop.com", // << ANPASSEN >>
Email = "admin@yourwebshop.com", // << ANPASSEN >>
EmailConfirmed = true,
CreatedDate = DateTimeOffset.UtcNow, // Custom Property auf ApplicationUser
LastActive = DateTimeOffset.UtcNow // Custom Property auf ApplicationUser
};
var createAdmin = await userManager.CreateAsync(adminUser, "SecureAdminPass123!"); // << ANPASSEN >>
if (createAdmin.Succeeded) if (createAdmin.Succeeded)
{ {
await userManager.AddToRoleAsync(adminUser, "Admin"); await userManager.AddToRoleAsync(adminUser, "Admin");
Console.WriteLine("Admin user created."); Console.WriteLine("Admin user created.");
} }
else else { Console.WriteLine($"Error creating admin user: {string.Join(", ", createAdmin.Errors.Select(e => e.Description))}"); }
{
Console.WriteLine($"Error creating admin user: {string.Join(", ", createAdmin.Errors.Select(e => e.Description))}");
}
} }
// Erstelle einen initialen Kunden-Benutzer und sein Customer-Profil (KOMBINIERT) var customerUser = await userManager.FindByEmailAsync("customer@yourwebshop.com");
var customerUser = await userManager.FindByEmailAsync("customer@yourwebshop.com"); // << ANPASSEN >>
if (customerUser == null) if (customerUser == null)
{ {
customerUser = new ApplicationUser // << KORREKT: ERSTELLT ApplicationUser >> customerUser = new ApplicationUser { UserName = "customer@yourwebshop.com", Email = "customer@yourwebshop.com", EmailConfirmed = true, CreatedDate = DateTimeOffset.UtcNow, LastActive = DateTimeOffset.UtcNow };
{ var createCustomer = await userManager.CreateAsync(customerUser, "SecureCustomerPass123!");
UserName = "customer@yourwebshop.com", // << ANPASSEN >>
Email = "customer@yourwebshop.com", // << ANPASSEN >>
EmailConfirmed = true,
CreatedDate = DateTimeOffset.UtcNow, // Custom Property auf ApplicationUser
LastActive = DateTimeOffset.UtcNow // Custom Property auf ApplicationUser
};
var createCustomer = await userManager.CreateAsync(customerUser, "SecureCustomerPass123!"); // << ANPASSEN >>
if (createCustomer.Succeeded) if (createCustomer.Succeeded)
{ {
await userManager.AddToRoleAsync(customerUser, "Customer"); await userManager.AddToRoleAsync(customerUser, "Customer");
Console.WriteLine("Customer user created."); Console.WriteLine("Customer user created.");
// Kombinierter Teil: Customer-Profil erstellen, direkt nach IdentityUser-Erstellung if (!await context.Customers.AnyAsync(c => c.AspNetUserId == customerUser.Id))
var customerProfile = await context.Customers.FirstOrDefaultAsync(c => c.AspNetUserId == customerUser.Id); // << KORREKT: SUCHT NACH AspNetUserId >>
if (customerProfile == null)
{ {
customerProfile = new Webshop.Domain.Entities.Customer var customerProfile = new Customer { AspNetUserId = customerUser.Id, FirstName = "Test", LastName = "Kunde" };
{
Id = Guid.NewGuid(),
AspNetUserId = customerUser.Id,
FirstName = "Test",
LastName = "Kunde"
};
context.Customers.Add(customerProfile); context.Customers.Add(customerProfile);
await context.SaveChangesAsync(); await context.SaveChangesAsync();
Console.WriteLine("Customer profile created for new customer user."); Console.WriteLine("Customer profile created for new customer user.");
} }
} }
else else { Console.WriteLine($"Error creating customer user: {string.Join(", ", createCustomer.Errors.Select(e => e.Description))}"); }
{
Console.WriteLine($"Error creating customer user: {string.Join(", ", createCustomer.Errors.Select(e => e.Description))}");
} }
} }
// --- ENDE DES TEMPOR<4F>REN SETUP-BLOCKS ---
}
catch (Exception ex) catch (Exception ex)
{ {
var logger = services.GetRequiredService<ILogger<Program>>(); var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred during database migration or user initialization."); logger.LogError(ex, "An error occurred during database migration or user initialization.");
} }
} // <-- Hier endet der using-Scope }
// --- START: HTTP REQUEST PIPELINE KONFIGURIEREN --- // Middleware f<>r Reverse-Proxies
// Middleware f<>r Forwarded Headers (wichtig bei Reverse-Proxies wie Nginx oder Load Balancern)
app.UseForwardedHeaders(new ForwardedHeadersOptions app.UseForwardedHeaders(new ForwardedHeadersOptions
{ {
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
}); });
// Swagger/SwaggerUI f<>r API-Dokumentation aktivieren // Swagger/SwaggerUI f<>r API-Dokumentation aktivieren
// F<>r die Produktion w<>re es sicherer, dies an `app.Environment.IsDevelopment()` zu binden if (app.Environment.IsDevelopment())
// if (app.Environment.IsDevelopment()) {
// { app.UseSwagger();
app.UseSwagger(); app.UseSwaggerUI();
app.UseSwaggerUI(); }
// }
// app.UseHttpsRedirection(); // Auskommentiert f<>r Docker HTTP-Entwicklung (da der Proxy HTTPS <20>bernimmt) // app.UseHttpsRedirection(); // Auskommentiert f<>r Docker HTTP-Entwicklung
// WICHTIG: Die Reihenfolge der Middleware ist entscheidend! // WICHTIG: Die Reihenfolge ist entscheidend!
app.UseAuthentication(); // Zuerst pr<70>fen, wer der Benutzer ist app.UseAuthentication();
app.UseAuthorization(); // Dann pr<70>fen, was der Benutzer darf app.UseAuthorization();
app.MapControllers(); // Stellt sicher, dass Ihre Controller als Endpunkte gemappt werden app.MapControllers();
// --- ENDE: HTTP REQUEST PIPELINE KONFIGURIEREN --- app.Run();
app.Run(); // Hier startet die Anwendung und blockiert die weitere Ausf<73>hrung

View File

@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using Webshop.Application.DTOs; using Webshop.Application.DTOs;
using Webshop.Application.DTOs.Auth; using Webshop.Application.DTOs.Auth;
using Webshop.Application.DTOs.Categories; // Korrigierter Namespace
using Webshop.Application.DTOs.Categorys; using Webshop.Application.DTOs.Categorys;
using Webshop.Application.DTOs.Customers; using Webshop.Application.DTOs.Customers;
using Webshop.Application.DTOs.Discounts; using Webshop.Application.DTOs.Discounts;
@@ -55,7 +56,7 @@ namespace Webshop.Api.SwaggerFilters
{ {
["isAuthSuccessful"] = new OpenApiBoolean(true), ["isAuthSuccessful"] = new OpenApiBoolean(true),
["errorMessage"] = new OpenApiString(""), ["errorMessage"] = new OpenApiString(""),
["token"] = new OpenApiString("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"), ["token"] = new OpenApiString("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."),
["userId"] = new OpenApiString(Guid.NewGuid().ToString()), ["userId"] = new OpenApiString(Guid.NewGuid().ToString()),
["email"] = new OpenApiString("loggedin@example.com"), ["email"] = new OpenApiString("loggedin@example.com"),
["roles"] = new OpenApiArray { new OpenApiString("Customer") } ["roles"] = new OpenApiArray { new OpenApiString("Customer") }
@@ -81,10 +82,7 @@ namespace Webshop.Api.SwaggerFilters
} }
else if (type == typeof(ResendEmailConfirmationRequestDto)) else if (type == typeof(ResendEmailConfirmationRequestDto))
{ {
schema.Example = new OpenApiObject schema.Example = new OpenApiObject { ["email"] = new OpenApiString("unconfirmed.user@example.com") };
{
["email"] = new OpenApiString("unconfirmed.user@example.com")
};
} }
else if (type == typeof(ChangePasswordRequestDto)) else if (type == typeof(ChangePasswordRequestDto))
{ {
@@ -149,43 +147,10 @@ namespace Webshop.Api.SwaggerFilters
["lastModifiedDate"] = new OpenApiNull(), ["lastModifiedDate"] = new OpenApiNull(),
["supplierId"] = new OpenApiNull(), ["supplierId"] = new OpenApiNull(),
["purchasePrice"] = new OpenApiDouble(80.00), ["purchasePrice"] = new OpenApiDouble(80.00),
["categoryIds"] = new OpenApiArray ["categoryIds"] = new OpenApiArray { new OpenApiString("EXISTING_CATEGORY_ID_HERE") }
{
new OpenApiString("EXISTING_CATEGORY_ID_1"),
new OpenApiString("EXISTING_CATEGORY_ID_2")
}
};
}
else if (type == typeof(ProductVariantDto))
{
schema.Example = new OpenApiObject
{
["id"] = new OpenApiString(Guid.Empty.ToString()),
["productId"] = new OpenApiString("EIN_PRODUKT_GUID_HIER"),
["name"] = new OpenApiString("Variante: Schwarz L"),
["value"] = new OpenApiString("Schwarz, L"),
["sku"] = new OpenApiString($"VARIANT-ABC-{uniqueId}"),
["priceAdjustment"] = new OpenApiDouble(5.00),
["stockQuantity"] = new OpenApiInteger(25),
["imageUrl"] = new OpenApiString("https://example.com/images/prod-variant-red.jpg"),
["isActive"] = new OpenApiBoolean(true)
}; };
} }
// --- Kategorien --- // --- Kategorien ---
else if (type == typeof(CategoryDto))
{
schema.Example = new OpenApiObject
{
["id"] = new OpenApiString(Guid.NewGuid().ToString()),
["name"] = new OpenApiString($"Elektronik {uniqueId}"),
["slug"] = new OpenApiString($"elektronik-{uniqueId}"),
["description"] = new OpenApiString("Produkte rund um Elektronik."),
["parentCategoryId"] = new OpenApiNull(),
["imageUrl"] = new OpenApiString("https://example.com/images/category_electronics.jpg"),
["isActive"] = new OpenApiBoolean(true),
["displayOrder"] = new OpenApiInteger(1)
};
}
else if (type == typeof(CreateCategoryDto)) else if (type == typeof(CreateCategoryDto))
{ {
schema.Example = new OpenApiObject schema.Example = new OpenApiObject
@@ -204,7 +169,7 @@ namespace Webshop.Api.SwaggerFilters
{ {
schema.Example = new OpenApiObject schema.Example = new OpenApiObject
{ {
["id"] = new OpenApiString(Guid.Empty.ToString()), ["id"] = new OpenApiString(Guid.NewGuid().ToString()),
["street"] = new OpenApiString("Musterstraße"), ["street"] = new OpenApiString("Musterstraße"),
["houseNumber"] = new OpenApiString("123a"), ["houseNumber"] = new OpenApiString("123a"),
["city"] = new OpenApiString("Musterstadt"), ["city"] = new OpenApiString("Musterstadt"),
@@ -214,20 +179,6 @@ namespace Webshop.Api.SwaggerFilters
}; };
} }
// --- Kunden --- // --- Kunden ---
else if (type == typeof(CustomerDto))
{
schema.Example = new OpenApiObject
{
["id"] = new OpenApiString(Guid.NewGuid().ToString()),
["userId"] = new OpenApiString("EIN_IDENTITY_USER_ID_HIER"),
["firstName"] = new OpenApiString("Max"),
["lastName"] = new OpenApiString("Mustermann"),
["email"] = new OpenApiString($"max.mustermann.{uniqueId}@example.com"),
["phoneNumber"] = new OpenApiString("+491719876543"),
["defaultShippingAddressId"] = new OpenApiNull(),
["defaultBillingAddressId"] = new OpenApiNull()
};
}
else if (type == typeof(UpdateCustomerDto)) else if (type == typeof(UpdateCustomerDto))
{ {
schema.Example = new OpenApiObject schema.Example = new OpenApiObject
@@ -240,32 +191,11 @@ namespace Webshop.Api.SwaggerFilters
["defaultBillingAddressId"] = new OpenApiNull() ["defaultBillingAddressId"] = new OpenApiNull()
}; };
} }
// --- Rabatte ---
else if (type == typeof(DiscountDto))
{
schema.Example = new OpenApiObject
{
["id"] = new OpenApiString(Guid.Empty.ToString()),
["name"] = new OpenApiString($"Sommerrabatt {uniqueId}"),
["description"] = new OpenApiString("10% Rabatt auf alles"),
["type"] = new OpenApiString(DiscountType.Percentage.ToString()),
["value"] = new OpenApiDouble(10.00),
["couponCode"] = new OpenApiString($"SOMMER-{uniqueId}"),
["startDate"] = new OpenApiString(DateTimeOffset.UtcNow.AddDays(1).ToString("o")),
["endDate"] = new OpenApiString(DateTimeOffset.UtcNow.AddDays(30).ToString("o")),
["isActive"] = new OpenApiBoolean(true),
["maxUses"] = new OpenApiInteger(100),
["currentUses"] = new OpenApiInteger(0)
};
}
// --- Bestellungen --- // --- Bestellungen ---
else if (type == typeof(CreateOrderDto)) else if (type == typeof(CreateOrderDto))
{ {
schema.Example = new OpenApiObject schema.Example = new OpenApiObject
{ {
["customerId"] = new OpenApiString("CUSTOMER_ID_HERE"),
["guestEmail"] = new OpenApiString($"gast.besteller.{uniqueId}@example.com"),
["guestPhoneNumber"] = new OpenApiString("+4917611223344"),
["shippingAddressId"] = new OpenApiString("VALID_ADDRESS_ID_HERE"), ["shippingAddressId"] = new OpenApiString("VALID_ADDRESS_ID_HERE"),
["billingAddressId"] = new OpenApiString("VALID_ADDRESS_ID_HERE"), ["billingAddressId"] = new OpenApiString("VALID_ADDRESS_ID_HERE"),
["paymentMethodId"] = new OpenApiString("VALID_PAYMENT_METHOD_ID_HERE"), ["paymentMethodId"] = new OpenApiString("VALID_PAYMENT_METHOD_ID_HERE"),
@@ -280,110 +210,6 @@ namespace Webshop.Api.SwaggerFilters
} }
}; };
} }
else if (type == typeof(CreateOrderItemDto))
{
schema.Example = new OpenApiObject
{
["productId"] = new OpenApiString("VALID_PRODUCT_ID_HERE"),
["productVariantId"] = new OpenApiNull(),
["quantity"] = new OpenApiInteger(1)
};
}
else if (type == typeof(OrderSummaryDto))
{
schema.Example = new OpenApiObject
{
["id"] = new OpenApiString(Guid.NewGuid().ToString()),
["orderNumber"] = new OpenApiString($"WS-2025-{uniqueId}"),
["orderDate"] = new OpenApiString(DateTimeOffset.UtcNow.ToString("o")),
["status"] = new OpenApiString(OrderStatus.Processing.ToString()),
["totalAmount"] = new OpenApiDouble(123.45),
["paymentStatus"] = new OpenApiString(PaymentStatus.Paid.ToString()),
["paymentMethodName"] = new OpenApiString("Kreditkarte"),
["shippingMethodName"] = new OpenApiString("Standardversand")
};
}
else if (type == typeof(OrderDetailDto))
{
schema.Example = new OpenApiObject
{
["id"] = new OpenApiString(Guid.NewGuid().ToString()),
["orderNumber"] = new OpenApiString($"WS-2025-{uniqueId}-Detail"),
["customerId"] = new OpenApiString(Guid.NewGuid().ToString()),
["orderDate"] = new OpenApiString(DateTimeOffset.UtcNow.ToString("o")),
["status"] = new OpenApiString(OrderStatus.Shipped.ToString()),
["totalAmount"] = new OpenApiDouble(245.67),
["shippingAddressId"] = new OpenApiString("EXISTING_ADDRESS_ID"),
["billingAddressId"] = new OpenApiString("EXISTING_ADDRESS_ID"),
["paymentMethodId"] = new OpenApiString("EXISTING_PAYMENT_METHOD_ID"),
["orderItems"] = new OpenApiArray {
new OpenApiObject { ["id"] = new OpenApiString(Guid.NewGuid().ToString()), ["productId"] = new OpenApiString("PROD_B_ID"), ["productName"] = new OpenApiString("Produkt B"), ["quantity"] = new OpenApiInteger(1), ["unitPrice"] = new OpenApiDouble(199.99), ["totalPrice"] = new OpenApiDouble(199.99) }
}
};
}
// --- Bewertungen ---
else if (type == typeof(ReviewDto))
{
schema.Example = new OpenApiObject
{
["id"] = new OpenApiString(Guid.NewGuid().ToString()),
["productId"] = new OpenApiString("EXISTING_PRODUCT_ID_HERE"),
["customerId"] = new OpenApiString("EXISTING_CUSTOMER_ID_HERE"),
["rating"] = new OpenApiInteger(5),
["title"] = new OpenApiString($"Super Produkt! ({uniqueId})"),
["comment"] = new OpenApiString("Ich bin sehr zufrieden mit diesem Produkt."),
["reviewDate"] = new OpenApiString(DateTimeOffset.UtcNow.ToString("o")),
["isApproved"] = new OpenApiBoolean(false)
};
}
else if (type == typeof(CreateReviewDto))
{
schema.Example = new OpenApiObject
{
["productId"] = new OpenApiString("EXISTING_PRODUCT_ID_HERE"),
["rating"] = new OpenApiInteger(4),
["title"] = new OpenApiString($"Gute Qualität ({uniqueId})"),
["comment"] = new OpenApiString("Das Produkt ist gut, aber die Lieferung dauerte etwas.")
};
}
// --- Einstellungen ---
else if (type == typeof(SettingDto))
{
schema.Example = new OpenApiObject
{
["key"] = new OpenApiString($"GlobalTaxRate-{uniqueId}"),
["value"] = new OpenApiString("0.19"),
["description"] = new OpenApiString("Allgemeiner Mehrwertsteuersatz"),
["lastModifiedDate"] = new OpenApiString(DateTimeOffset.UtcNow.ToString("o"))
};
}
// --- Zahlungsmethoden ---
else if (type == typeof(PaymentMethodDto))
{
schema.Example = new OpenApiObject
{
["id"] = new OpenApiString(Guid.Empty.ToString()),
["name"] = new OpenApiString($"Kreditkarte (Stripe) {uniqueId}"),
["description"] = new OpenApiString("Online-Zahlungsdienstleister."),
["isActive"] = new OpenApiBoolean(true),
["gatewayType"] = new OpenApiString(PaymentGatewayType.Stripe.ToString()),
["processingFee"] = new OpenApiDouble(0.035)
};
}
// --- Versandmethoden ---
else if (type == typeof(ShippingMethodDto))
{
schema.Example = new OpenApiObject
{
["id"] = new OpenApiString(Guid.Empty.ToString()),
["name"] = new OpenApiString($"Expressversand UPS {uniqueId}"),
["description"] = new OpenApiString("Lieferung am nächsten Werktag."),
["cost"] = new OpenApiDouble(12.50),
["isActive"] = new OpenApiBoolean(true),
["minDeliveryDays"] = new OpenApiInteger(1),
["maxDeliveryDays"] = new OpenApiInteger(1)
};
}
} }
} }
} }

View File

@@ -0,0 +1,59 @@
// src/Webshop.Api/SwaggerFilters/ShippingMethodExampleOperationFilter.cs
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Microsoft.OpenApi.Any;
using System.Net.Mime;
using System.Collections.Generic;
namespace Webshop.Api.SwaggerFilters
{
public class ShippingMethodExampleOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (context.MethodInfo.DeclaringType == typeof(Controllers.Admin.AdminShippingMethodsController) &&
context.MethodInfo.Name == "CreateShippingMethod")
{
if (operation.RequestBody == null ||
!operation.RequestBody.Content.TryGetValue(MediaTypeNames.Application.Json, out var mediaType))
{
return;
}
if (mediaType.Examples == null)
{
mediaType.Examples = new Dictionary<string, OpenApiExample>();
}
mediaType.Examples.Clear();
mediaType.Examples["Standard"] = new OpenApiExample
{
Summary = "Beispiel: Standardversand",
Value = new OpenApiObject
{
["name"] = new OpenApiString("Standardversand (DHL)"),
["description"] = new OpenApiString("Lieferung in 2-3 Werktagen."),
["cost"] = new OpenApiDouble(4.99),
["isActive"] = new OpenApiBoolean(true),
["minDeliveryDays"] = new OpenApiInteger(2),
["maxDeliveryDays"] = new OpenApiInteger(3)
}
};
mediaType.Examples["Express"] = new OpenApiExample
{
Summary = "Beispiel: Expressversand",
Value = new OpenApiObject
{
["name"] = new OpenApiString("Expressversand (UPS)"),
["description"] = new OpenApiString("Lieferung am nächsten Werktag."),
["cost"] = new OpenApiDouble(12.99),
["isActive"] = new OpenApiBoolean(true),
["minDeliveryDays"] = new OpenApiInteger(1),
["maxDeliveryDays"] = new OpenApiInteger(1)
}
};
}
}
}
}