Files
Elternbeirat/Elternbeirat.Web/Program.cs
T

68 lines
2.3 KiB
C#

using Elternbeirat.Contracts;
using Elternbeirat.PocketBase;
using Elternbeirat.Web.Components;
using Elternbeirat.Web.Features.Events;
using Microsoft.AspNetCore.HttpOverrides;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorComponents();
// The typed client reads content from PocketBase over its REST API. The base URL
// comes from configuration: appsettings for local dev, the PocketBase__BaseUrl
// env var on the server (see compose.yaml).
var pocketBaseUrl = builder.Configuration["PocketBase:BaseUrl"]
?? throw new InvalidOperationException("PocketBase:BaseUrl is not configured.");
builder.Services.AddHttpClient<PocketBaseClient>(client =>
client.BaseAddress = new Uri(pocketBaseUrl));
var app = builder.Build();
// NPM terminates TLS and is the only way to reach the container (no port
// mapping in production). Without UseForwardedHeaders the app sees every request
// as HTTP and with the proxy IP instead of the client IP.
// KnownNetworks/KnownProxies are deliberately empty because only NPM reaches
// the container.
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
KnownIPNetworks = { },
KnownProxies = { }
});
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// No UseHsts() and no UseHttpsRedirection(): NPM sets HSTS and terminates
// TLS. Both here would create a redirect loop behind the proxy.
}
app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);
app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents<App>();
// Subscribable calendar feed of all events. A minimal API endpoint rather than
// a Razor page because it returns text/calendar, not HTML. Reads from PocketBase
// per request; an unreachable source yields an empty calendar, not a 500.
app.MapGet("/events.ics", async (PocketBaseClient pocketBase) =>
{
IReadOnlyList<Event> events;
try
{
events = await pocketBase.GetEventsAsync();
}
catch (HttpRequestException)
{
events = [];
}
return Results.Text(IcsCalendar.Build(events), "text/calendar; charset=utf-8");
});
app.Run();