// 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);
}
}