Wp2ghost/GhostImageManager/Program.cs
2026-10-14 19:12:29 +02:00

160 lines
5.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using GhostImageManager.Components;
using GhostImageManager.Data;
using GhostImageManager.Models;
using GhostImageManager.Services;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.EntityFrameworkCore;
using Serilog;
var builder = WebApplication.CreateBuilder(args);
// Logging konfigurieren
var logsDir = Path.Combine(builder.Environment.ContentRootPath, "logs");
if (!Directory.Exists(logsDir))
Directory.CreateDirectory(logsDir);
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.AspNetCore", Serilog.Events.LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.File(
Path.Combine(logsDir, "ghost-image-manager-.log"),
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 30,
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.CreateLogger();
builder.Host.UseSerilog();
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
// Datenbank
var dbPath = Path.Combine(builder.Environment.ContentRootPath, "ghost-image-manager.db");
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlite($"Data Source={dbPath}"));
builder.Services.Configure<AppSettings>(builder.Configuration.GetSection("AppSettings"));
builder.Services.AddSingleton<GhostConfigService>();
builder.Services.AddScoped<GhostApiService>();
builder.Services.AddScoped<ImageAnalyzerService>();
builder.Services.AddScoped<ImageReplacementService>();
builder.Services.AddScoped<ImageDeletionService>();
builder.Services.AddScoped<ImageExportService>();
builder.Services.AddScoped<ImageDatabaseService>();
builder.Services.AddScoped<ExifService>();
builder.Services.AddScoped<AuthService>();
builder.Services.AddSingleton<LogService>();
builder.Services.AddHttpClient<GhostApiService>();
// Authentication
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/login";
options.LogoutPath = "/logout";
options.AccessDeniedPath = "/access-denied";
options.ExpireTimeSpan = TimeSpan.FromMinutes(480);
options.SlidingExpiration = true;
});
builder.Services.AddAuthorization();
builder.Services.AddCascadingAuthenticationState();
// Upload-Limit erhöhen (für Bildtausch)
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.MaxRequestBodySize = 104857600; // 100 MB
});
var app = builder.Build();
// Datenbank sicherstellen
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
db.Database.EnsureCreated();
// EnsureCreated ergänzt keine Spalten in einer bestehenden DB – später hinzugekommene nachziehen
var existingColumns = db.Database.SqlQueryRaw<string>("SELECT name AS Value FROM pragma_table_info('ManagedImages')").ToList();
foreach (var (column, type) in new[]
{
("Category", "TEXT NULL"),
("CategorySecondary", "TEXT NULL"),
("HasMultipleCategories", "INTEGER NOT NULL DEFAULT 0"),
("Keywords", "TEXT NULL")
})
{
if (!existingColumns.Contains(column, StringComparer.OrdinalIgnoreCase))
db.Database.ExecuteSqlRaw($"ALTER TABLE ManagedImages ADD COLUMN {column} {type}");
}
}
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
app.UseHsts();
}
app.UseHttpsRedirection();
// Standard wwwroot
app.UseStaticFiles();
// Zusätzlich: start.jpg aus dem App-Root ausliefern
var rootImagePath = Path.Combine(app.Environment.ContentRootPath, "start.jpg");
if (File.Exists(rootImagePath))
{
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new Microsoft.Extensions.FileProviders.PhysicalFileProvider(app.Environment.ContentRootPath),
RequestPath = "/start-image"
});
}
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
// Authentication API endpoints
app.MapPost("/auth/login", async (HttpContext context, AuthService authService, ILogger<Program> logger) =>
{
var form = await context.Request.ReadFormAsync();
var password = form["password"].ToString();
var returnUrl = form["returnUrl"].ToString();
if (string.IsNullOrEmpty(returnUrl))
returnUrl = "/";
try
{
logger.LogInformation("Benutzer meldet sich an");
await authService.SignInAsync(context, password);
logger.LogInformation("Anmeldung erfolgreich");
return Results.Redirect(returnUrl);
}
catch (UnauthorizedAccessException)
{
logger.LogWarning("Fehlgeschlagene Anmeldung");
return Results.Redirect($"/login?errorMessage={Uri.EscapeDataString("Ungültiges Passwort.")}&returnUrl={Uri.EscapeDataString(returnUrl)}");
}
});
app.MapPost("/auth/logout", async (HttpContext context, AuthService authService, ILogger<Program> logger) =>
{
logger.LogInformation("Benutzer meldet sich ab");
await authService.SignOutAsync(context);
return Results.Redirect("/login");
});
app.Run();
Log.CloseAndFlush();