// Deze usings staan er expliciet bij. In het webproject komen ze vanzelf mee, maar zo is het // bestand ook los te compileren - en daar wordt het in de controle op nagekeken. using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using MijnBesluit.Application.Services; namespace MijnBesluit.Web; /// /// Het ophalen van een bijlage. /// /// Dit staat bewust in een eigen bestand en niet in Program.cs: zo valt het binnen het /// controleproject dat de pagina's compileert, en wordt het dus meegenomen als er iets /// verandert aan de Application-laag. /// public static class Bestanden { public static void MapBijlagen(this WebApplication app) { // Bewust een eigen adres en niet de Blazor-verbinding: een bestand van tientallen // megabytes daardoorheen duwen is traag en houdt die verbinding bezet. // // Twee adressen naar dezelfde afhandeling. Een bijlage hangt tegenwoordig ook aan een // persoon of aan een bericht, dus "kluis" klopt niet meer; /bestand is de naam die // blijft. Het oude adres blijft staan zolang er nog schermen open kunnen zijn die het // gebruiken - dat kost niets en voorkomt een kapot plaatje net na een uitrol. app.MapGet("/bestand/{id:long}", Geef).RequireAuthorization(); app.MapGet("/kluis/bestand/{id:long}", Geef).RequireAuthorization(); // De kleine versie, voor in lijstjes. Is die er niet - een foto van voor deze wijziging, // of een bestand dat geen afbeelding is - dan komt het bestand zelf terug. Zo hoeft het // scherm niet te weten of er al een kleine versie bestaat. app.MapGet("/bestand/{id:long}/klein", async (long id, HttpContext context, VaultService kluis) => { var gebruikerId = context.User.UserId(); if (gebruikerId is null) return Results.Unauthorized(); var klein = await kluis.OpenThumbnailAsync(id, gebruikerId.Value, context.RequestAborted); if (klein.Succeeded) return Results.File(klein.Value!, "image/jpeg"); return await Geef(id, context, kluis); }).RequireAuthorization(); // De bijlage bij een moment dat via een kijklink wordt bekeken - dus zonder inloggen. // Geen {id}: het token op zich bewijst al bij welk bericht je hoort, en dat bericht // heeft hoogstens één bijlage. Bewust GEEN RequireAuthorization: dat is nou juist het // hele punt van deze link. app.MapGet("/moment/{token}/bestand", async (string token, MessageService berichten, HttpContext context) => { var resultaat = await berichten.OpenAttachmentByTokenAsync(token, context.RequestAborted); if (!resultaat.Succeeded) return Results.NotFound(resultaat.Error); var bestand = resultaat.Value.Bestand; var inScherm = bestand.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase) || bestand.ContentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase); return Results.File(resultaat.Value.Inhoud, bestand.ContentType, fileDownloadName: inScherm ? null : bestand.FileName); }); } private static async Task Geef(long id, HttpContext context, VaultService kluis) { var gebruikerId = context.User.UserId(); if (gebruikerId is null) return Results.Unauthorized(); var resultaat = await kluis.OpenFileAsync(id, gebruikerId.Value, context.RequestAborted); if (!resultaat.Succeeded) return Results.NotFound(resultaat.Error); var bestand = resultaat.Value.Bestand; var inhoud = resultaat.Value.Inhoud; // Afbeeldingen en video's laten we in het scherm zien; de rest wordt gedownload. var inScherm = bestand.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase) || bestand.ContentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase); return Results.File(inhoud, bestand.ContentType, fileDownloadName: inScherm ? null : bestand.FileName); } }