example values und aufräumen
This commit is contained in:
@@ -1,45 +1,47 @@
|
||||
// --- Core Frameworks & Libraries ---
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.HttpOverrides; // For UseForwardedHeaders
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging; // For ILogger
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.OpenApi.Models; // For Swagger OpenAPI models
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Resend;
|
||||
using System.Text;
|
||||
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.Auth; // IAuthService, AuthService
|
||||
using Webshop.Application.Services.Auth;
|
||||
using Webshop.Application.Services.Customers;
|
||||
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.Domain.Entities;
|
||||
using Webshop.Domain.Identity;
|
||||
using Webshop.Domain.Interfaces; // IProductRepository
|
||||
using Webshop.Infrastructure.Data; // ApplicationDbContext
|
||||
using Webshop.Infrastructure.Repositories; // ProductRepository
|
||||
using Webshop.Domain.Interfaces;
|
||||
using Webshop.Infrastructure.Data;
|
||||
using Webshop.Infrastructure.Repositories;
|
||||
|
||||
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 =>
|
||||
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 =>
|
||||
{
|
||||
options.SignIn.RequireConfirmedAccount = true;
|
||||
options.SignIn.RequireConfirmedEmail = true;
|
||||
})
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>() // Stellen Sie sicher, dass Ihr DbContext-Name hier korrekt ist
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>()
|
||||
.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 =>
|
||||
{
|
||||
options.Password.RequireDigit = false;
|
||||
@@ -47,14 +49,11 @@ builder.Services.Configure<IdentityOptions>(options =>
|
||||
options.Password.RequireNonAlphanumeric = false;
|
||||
options.Password.RequireUppercase = false;
|
||||
options.Password.RequireLowercase = false;
|
||||
options.SignIn.RequireConfirmedEmail = true; // F<>r einfache Entwicklung/Tests
|
||||
});
|
||||
|
||||
|
||||
// 3. JWT-Authentifizierung konfigurieren
|
||||
// JWT-Authentifizierung
|
||||
var jwtSettings = builder.Configuration.GetSection("JwtSettings");
|
||||
var secretKey = jwtSettings["Secret"] ?? throw new InvalidOperationException("JWT Secret not found in configuration.");
|
||||
|
||||
builder.Services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
@@ -73,9 +72,8 @@ builder.Services.AddAuthentication(options =>
|
||||
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
|
||||
builder.Services.AddScoped<IProductRepository, ProductRepository>();
|
||||
builder.Services.AddScoped<ISupplierRepository, SupplierRepository>();
|
||||
@@ -85,114 +83,94 @@ builder.Services.AddScoped<ICategoryRepository, CategoryRepository>();
|
||||
builder.Services.AddScoped<IOrderRepository, OrderRepository>();
|
||||
builder.Services.AddScoped<IShippingMethodRepository, ShippingMethodRepository>();
|
||||
builder.Services.AddScoped<IAddressRepository, AddressRepository>();
|
||||
// AUTH Services
|
||||
builder.Services.AddScoped<IAuthService, AuthService>();
|
||||
builder.Services.AddScoped<IDiscountRepository, DiscountRepository>();
|
||||
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<IPaymentMethodService, PaymentMethodService>();
|
||||
builder.Services.AddScoped<ICategoryService, CategoryService>();
|
||||
builder.Services.AddScoped<ICategoryService, CategoryService>();
|
||||
|
||||
// ADMIN Services
|
||||
builder.Services.AddScoped<IAdminUserService, AdminUserService>();
|
||||
builder.Services.AddScoped<IAdminProductService, AdminProductService>();
|
||||
builder.Services.AddScoped<IAdminSupplierService, AdminSupplierService>();
|
||||
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<IAdminShippingMethodService, AdminShippingMethodService>();
|
||||
|
||||
//builder.Services.AddScoped<IAdminDiscountService, AdminDiscountService>(); // Hinzugef<65>gt f<>r Konsistenz
|
||||
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<IAdminDiscountService, AdminDiscountService>();
|
||||
builder.Services.AddScoped<IAdminSettingService, AdminSettingService>();
|
||||
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<ICheckoutService, CheckoutService>(); // Hinzugef<65>gt f<>r Konsistenz
|
||||
//builder.Services.AddScoped<IReviewService, ReviewService>(); // Hinzugef<65>gt f<>r Konsistenz
|
||||
builder.Services.AddScoped<ICheckoutService, CheckoutService>();
|
||||
builder.Services.AddScoped<IReviewService, ReviewService>();
|
||||
|
||||
// --- NEU: Resend E-Mail-Dienst konfigurieren ---
|
||||
builder.Services.AddOptions(); // Stellt sicher, dass Options konfiguriert werden k<>nnen
|
||||
builder.Services.AddHttpClient<ResendClient>(); // F<>gt HttpClient f<>r Resend hinzu
|
||||
// Externe Dienste (Resend)
|
||||
builder.Services.AddHttpClient<ResendClient>();
|
||||
builder.Services.Configure<ResendClientOptions>(options =>
|
||||
{
|
||||
// Der API-Token kommt aus den Konfigurationen (z.B. appsettings.json oder Umgebungsvariablen)
|
||||
options.ApiToken = builder.Configuration["Resend:ApiToken"]!; // << ANPASSEN >>
|
||||
options.ApiToken = builder.Configuration["Resend:ApiToken"]!;
|
||||
});
|
||||
builder.Services.AddTransient<IResend, ResendClient>();
|
||||
|
||||
|
||||
// 5. Controller und Swagger/OpenAPI hinzuf<75>gen
|
||||
// Controller und API-Infrastruktur
|
||||
builder.Services.AddControllers()
|
||||
.AddJsonOptions(options =>
|
||||
{
|
||||
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
|
||||
});
|
||||
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
|
||||
// Swagger / OpenAPI Konfiguration
|
||||
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
|
||||
{
|
||||
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
|
||||
Description = "JWT Authorization header. Example: \"Authorization: Bearer {token}\"",
|
||||
Name = "Authorization",
|
||||
In = ParameterLocation.Header, // Der Token wird im Header gesendet
|
||||
Type = SecuritySchemeType.Http, // Dies ist ein HTTP-Schema
|
||||
Scheme = "Bearer" // Das Schema ist "Bearer"
|
||||
In = ParameterLocation.Header,
|
||||
Type = SecuritySchemeType.Http,
|
||||
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.SchemaFilter<AddExampleSchemaFilter>();
|
||||
|
||||
c.OperationFilter<LoginExampleOperationFilter>();
|
||||
c.OperationFilter<PaymentMethodExampleOperationFilter>();
|
||||
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
|
||||
// OPTIONALE BL<42>CKE F<>R MIGRATION UND BENUTZERINITIALISIERUNG - DIESER CODE WIRD VOR APP.RUN() AUSGEF<45>HRT
|
||||
var app = builder.Build();
|
||||
|
||||
// F<>hre Datenbank-Migrationen und Initialisierungslogik beim Start aus
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var services = scope.ServiceProvider;
|
||||
try
|
||||
{
|
||||
var context = services.GetRequiredService<ApplicationDbContext>();
|
||||
// Wendet ausstehende Datenbank-Migrationen an (sehr n<>tzlich f<>r Entwicklung/Tests)
|
||||
context.Database.Migrate();
|
||||
|
||||
// --- TEMPOR<4F>RER INITIALER ADMIN- UND KUNDEN-SETUP (NUR F<>R ERSTE ENTWICKLUNG!) ---
|
||||
// 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!
|
||||
// TEMPOR<4F>RER INITIALER ADMIN- UND KUNDEN-SETUP
|
||||
// HINWEIS: Dieser Block sollte in der Produktion entfernt oder deaktiviert werden.
|
||||
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" };
|
||||
|
||||
foreach (var roleName in roleNames)
|
||||
{
|
||||
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"); // << ANPASSEN >>
|
||||
var adminUser = await userManager.FindByEmailAsync("admin@yourwebshop.com");
|
||||
if (adminUser == null)
|
||||
{
|
||||
adminUser = new ApplicationUser // << KORREKT: ERSTELLT ApplicationUser >>
|
||||
{
|
||||
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 >>
|
||||
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!");
|
||||
if (createAdmin.Succeeded)
|
||||
{
|
||||
await userManager.AddToRoleAsync(adminUser, "Admin");
|
||||
Console.WriteLine("Admin user created.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Error creating admin user: {string.Join(", ", createAdmin.Errors.Select(e => e.Description))}");
|
||||
}
|
||||
else { 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"); // << ANPASSEN >>
|
||||
var customerUser = await userManager.FindByEmailAsync("customer@yourwebshop.com");
|
||||
if (customerUser == null)
|
||||
{
|
||||
customerUser = new ApplicationUser // << KORREKT: ERSTELLT ApplicationUser >>
|
||||
{
|
||||
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 >>
|
||||
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!");
|
||||
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)
|
||||
if (!await context.Customers.AnyAsync(c => c.AspNetUserId == customerUser.Id))
|
||||
{
|
||||
customerProfile = new Webshop.Domain.Entities.Customer
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
AspNetUserId = customerUser.Id,
|
||||
FirstName = "Test",
|
||||
LastName = "Kunde"
|
||||
};
|
||||
var customerProfile = new Customer { 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))}");
|
||||
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)
|
||||
{
|
||||
var logger = services.GetRequiredService<ILogger<Program>>();
|
||||
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 Forwarded Headers (wichtig bei Reverse-Proxies wie Nginx oder Load Balancern)
|
||||
// Middleware f<>r Reverse-Proxies
|
||||
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
||||
{
|
||||
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
|
||||
});
|
||||
|
||||
// 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.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!
|
||||
app.UseAuthentication(); // Zuerst pr<70>fen, wer der Benutzer ist
|
||||
app.UseAuthorization(); // Dann pr<70>fen, was der Benutzer darf
|
||||
// WICHTIG: Die Reihenfolge ist entscheidend!
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers(); // Stellt sicher, dass Ihre Controller als Endpunkte gemappt werden
|
||||
app.MapControllers();
|
||||
|
||||
// --- ENDE: HTTP REQUEST PIPELINE KONFIGURIEREN ---
|
||||
|
||||
app.Run(); // Hier startet die Anwendung und blockiert die weitere Ausf<73>hrung
|
||||
app.Run();
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Webshop.Application.DTOs;
|
||||
using Webshop.Application.DTOs.Auth;
|
||||
using Webshop.Application.DTOs.Categories; // Korrigierter Namespace
|
||||
using Webshop.Application.DTOs.Categorys;
|
||||
using Webshop.Application.DTOs.Customers;
|
||||
using Webshop.Application.DTOs.Discounts;
|
||||
@@ -55,7 +56,7 @@ namespace Webshop.Api.SwaggerFilters
|
||||
{
|
||||
["isAuthSuccessful"] = new OpenApiBoolean(true),
|
||||
["errorMessage"] = new OpenApiString(""),
|
||||
["token"] = new OpenApiString("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"),
|
||||
["token"] = new OpenApiString("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."),
|
||||
["userId"] = new OpenApiString(Guid.NewGuid().ToString()),
|
||||
["email"] = new OpenApiString("loggedin@example.com"),
|
||||
["roles"] = new OpenApiArray { new OpenApiString("Customer") }
|
||||
@@ -81,10 +82,7 @@ namespace Webshop.Api.SwaggerFilters
|
||||
}
|
||||
else if (type == typeof(ResendEmailConfirmationRequestDto))
|
||||
{
|
||||
schema.Example = new OpenApiObject
|
||||
{
|
||||
["email"] = new OpenApiString("unconfirmed.user@example.com")
|
||||
};
|
||||
schema.Example = new OpenApiObject { ["email"] = new OpenApiString("unconfirmed.user@example.com") };
|
||||
}
|
||||
else if (type == typeof(ChangePasswordRequestDto))
|
||||
{
|
||||
@@ -149,43 +147,10 @@ namespace Webshop.Api.SwaggerFilters
|
||||
["lastModifiedDate"] = new OpenApiNull(),
|
||||
["supplierId"] = new OpenApiNull(),
|
||||
["purchasePrice"] = new OpenApiDouble(80.00),
|
||||
["categoryIds"] = new OpenApiArray
|
||||
{
|
||||
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)
|
||||
["categoryIds"] = new OpenApiArray { new OpenApiString("EXISTING_CATEGORY_ID_HERE") }
|
||||
};
|
||||
}
|
||||
// --- 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))
|
||||
{
|
||||
schema.Example = new OpenApiObject
|
||||
@@ -204,7 +169,7 @@ namespace Webshop.Api.SwaggerFilters
|
||||
{
|
||||
schema.Example = new OpenApiObject
|
||||
{
|
||||
["id"] = new OpenApiString(Guid.Empty.ToString()),
|
||||
["id"] = new OpenApiString(Guid.NewGuid().ToString()),
|
||||
["street"] = new OpenApiString("Musterstraße"),
|
||||
["houseNumber"] = new OpenApiString("123a"),
|
||||
["city"] = new OpenApiString("Musterstadt"),
|
||||
@@ -214,20 +179,6 @@ namespace Webshop.Api.SwaggerFilters
|
||||
};
|
||||
}
|
||||
// --- 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))
|
||||
{
|
||||
schema.Example = new OpenApiObject
|
||||
@@ -240,32 +191,11 @@ namespace Webshop.Api.SwaggerFilters
|
||||
["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 ---
|
||||
else if (type == typeof(CreateOrderDto))
|
||||
{
|
||||
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"),
|
||||
["billingAddressId"] = new OpenApiString("VALID_ADDRESS_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)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user