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,155 @@
using System.Net.Http.Json;
using LehrerApp.Core.Interfaces;
using LehrerApp.Core.Models;
using LehrerApp.Core.Services;
namespace LehrerApp.Sync;
/// <summary>
/// Exportiert einen lesbaren Snapshot der lokalen LiteDB
/// und pusht ihn zur API wo er für die WebApp abrufbar ist.
///
/// Wird automatisch nach jedem Sync-Zyklus ausgeführt
/// und kann manuell angestoßen werden.
/// </summary>
public class ReadableSnapshotService
{
private readonly HttpClient _http;
private readonly IStudentRepository _students;
private readonly IGroupRepository _groups;
private readonly IEnrollmentRepository _enrollments;
private readonly IExamRepository _exams;
private readonly IExamResultRepository _examResults;
private readonly IGradeRepository _grades;
private readonly IUnitRepository _units;
private readonly ILessonRepository _lessons;
private readonly IWorkTaskRepository _tasks;
private readonly SchoolYearService _schoolYear;
private readonly string _deviceId;
public event Action<string>? StatusChanged;
public ReadableSnapshotService(
HttpClient http,
IStudentRepository students,
IGroupRepository groups,
IEnrollmentRepository enrollments,
IExamRepository exams,
IExamResultRepository examResults,
IGradeRepository grades,
IUnitRepository units,
ILessonRepository lessons,
IWorkTaskRepository tasks,
SchoolYearService schoolYear,
string deviceId)
{
_http = http;
_students = students;
_groups = groups;
_enrollments = enrollments;
_exams = exams;
_examResults = examResults;
_grades = grades;
_units = units;
_lessons = lessons;
_tasks = tasks;
_schoolYear = schoolYear;
_deviceId = deviceId;
}
// ── Export ────────────────────────────────────────────────────────────────
public async Task<bool> ExportAndPushAsync(
CancellationToken ct = default)
{
StatusChanged?.Invoke("Snapshot wird erstellt…");
try
{
var snapshot = BuildSnapshot();
StatusChanged?.Invoke("Snapshot wird übertragen…");
var response = await _http.PostAsJsonAsync(
"/api/snapshot/readable", snapshot, ct);
if (!response.IsSuccessStatusCode)
{
StatusChanged?.Invoke(
$"Übertragung fehlgeschlagen: {response.StatusCode}");
return false;
}
StatusChanged?.Invoke(
$"Snapshot übertragen {snapshot.Meta.StudentCount} Schüler, " +
$"{snapshot.Meta.GroupCount} Gruppen");
return true;
}
catch (Exception ex)
{
StatusChanged?.Invoke($"Fehler: {ex.Message}");
return false;
}
}
// ── Snapshot aufbauen ─────────────────────────────────────────────────────
private ReadableSnapshot BuildSnapshot()
{
var schoolYear = _schoolYear.CurrentSchoolYear();
var groups = _groups.GetBySchoolYear(schoolYear);
var groupIds = groups.Select(g => g.Id).ToHashSet();
var students = _students.GetAll();
var enrollments = groups
.SelectMany(g => _enrollments.GetByGroupAndYear(g.Id, schoolYear))
.ToList();
var exams = groupIds
.SelectMany(gid => _exams.GetByGroup(gid))
.ToList();
var examResults = exams
.SelectMany(e => _examResults.GetByExam(e.Id))
.ToList();
var grades = groupIds
.SelectMany(gid => _grades.GetByGroup(gid))
.ToList();
var units = groupIds
.SelectMany(gid => _units.GetByGroup(gid))
.ToList();
var lessons = units
.SelectMany(u => _lessons.GetByUnit(u.Id))
.ToList();
var tasks = _tasks.GetAll()
.Where(t => t.Status != WorkTaskStatus.Done)
.ToList();
var snapshot = new ReadableSnapshot
{
SchoolYear = schoolYear,
Students = students,
Groups = groups,
Enrollments = enrollments,
Exams = exams,
ExamResults = examResults,
Grades = grades,
Units = units,
Lessons = lessons,
Tasks = tasks,
Meta = new SnapshotMeta
{
StudentCount = students.Count,
GroupCount = groups.Count,
ExamCount = exams.Count,
ExportedByDevice = _deviceId,
OldestData = DateTime.UtcNow.AddYears(-1), // vereinfacht
},
};
return snapshot;
}
}