This commit is contained in:
2026-03-29 23:47:31 +02:00
commit 216d5d2280
75 changed files with 5702 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
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);
});
}
}