Files
LehrerApp/LehrerApp.Api/Endpoints/ReadableSnapshotEndpoints.cs
2026-03-29 23:47:31 +02:00

116 lines
4.0 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 System.Security.Claims;
using LehrerApp.Core.Models;
using LehrerApp.Sync.Models;
using Microsoft.AspNetCore.Mvc;
namespace LehrerApp.Api;
public static class ReadableSnapshotEndpoints
{
// ── Readable Snapshot ─────────────────────────────────────────────────────
public static void MapReadableSnapshotEndpoints(this WebApplication app)
{
var snap = app.MapGroup("/api/snapshot/readable")
.RequireAuthorization();
// Desktop → Server: aktuellen Snapshot hochladen
snap.MapPost("/", (
[FromBody] ReadableSnapshot snapshot,
ClaimsPrincipal user,
ReadableSnapshotStore store) =>
{
var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (userId is null) return Results.Unauthorized();
snapshot.ExportedAt = DateTime.UtcNow;
store.Store(userId, snapshot);
return Results.Ok(new
{
exportedAt = snapshot.ExportedAt,
studentCount = snapshot.Meta.StudentCount,
groupCount = snapshot.Meta.GroupCount,
});
});
// WebApp → Server: Snapshot laden
snap.MapGet("/", (
ClaimsPrincipal user,
ReadableSnapshotStore store) =>
{
var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (userId is null) return Results.Unauthorized();
var snapshot = store.Load(userId);
if (snapshot is null)
return Results.NotFound(
"Kein Snapshot vorhanden. " +
"Bitte zuerst den Desktop-Client mit dem Server verbinden.");
return Results.Ok(snapshot);
});
// Nur Metadaten für Freshness-Check der WebApp
snap.MapGet("/meta", (
ClaimsPrincipal user,
ReadableSnapshotStore store) =>
{
var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (userId is null) return Results.Unauthorized();
var meta = store.LoadMeta(userId);
if (meta is null) return Results.NotFound();
return Results.Ok(meta);
});
}
// ── Plain Sync (WebApp → EventStore) ─────────────────────────────────────
public static void MapPlainSyncEndpoints(this WebApplication app)
{
var sync = app.MapGroup("/api/sync/plain")
.RequireAuthorization();
// WebApp schreibt Events (Klartext) werden beim Desktop-Pull abgeholt
sync.MapPost("/push", (
[FromBody] List<PlainSyncEvent> events,
ClaimsPrincipal user,
PlainEventStore store) =>
{
var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (userId is null) return Results.Unauthorized();
// Nur erlaubte EntityTypes für WebApp-Schreibzugriff
var allowed = new HashSet<string>
{
"Grade", "ExamResult", "WorkTask", "Lesson"
};
var rejected = events
.Where(e => !allowed.Contains(e.EntityType))
.Select(e => e.EventId)
.ToList();
var permitted = events
.Where(e => allowed.Contains(e.EntityType))
.ToList();
PlainPushResponse result;
if (permitted.Count > 0)
result = store.Push(userId, permitted);
else
result = new PlainPushResponse { Success = true };
// Abgelehnte Events mit Grund zurückmelden
result = result with
{
RejectedEventIds = [.. result.RejectedEventIds, .. rejected],
};
return Results.Ok(result);
});
}
}