Die Übersicht wirkte beim Öffnen spürbar zeitverzögert, obwohl Fehlzeiten und Klassenbuch schon lokal gecacht waren (Nutzer-Feedback: "fühlt sich an wie ein Live-Pull mit CSV-Parsing"). Grund: genau das passierte - der Schülerreport (Namen fürs Roster) lief komplett am Cache vorbei bei jedem Öffnen live gegen WebUntis. Neues UntisStudentRosterCacheEntry/UntisStudentRosterCacheRepository (gleiches "kein db.OnChange"-Prinzip wie die bestehenden Caches) plus UntisReportCacheService.GetStudentRosterAsync - ohne heißes/kaltes Fenster, da eine Klassenliste keine Historie hat, nur dieselbe Stundenschwelle "gilt der letzte Abruf noch als frisch". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
80 lines
3.7 KiB
C#
80 lines
3.7 KiB
C#
namespace LehrerApp.Core.Models;
|
|
|
|
/// <summary>
|
|
/// Lokal zwischengespeicherte Zeile aus dem WebUntis-Bericht "Fehlzeiten pro Schüler*in"
|
|
/// (Klassenlehrer-Feature, siehe TODO.md) — 1:1-Abbildung von `UntisClassAbsenceEntryDto`
|
|
/// (LehrerApp.Desktop), damit Fehlzeiten nicht bei jedem Öffnen der Ansicht neu abgerufen werden
|
|
/// müssen. <c>Date</c> bewusst als <c>int</c> (yyyyMMdd) wie die DTOs statt <c>DateOnly</c>/
|
|
/// <c>DateTime</c> — vermeidet die LiteDB-<c>DateTime</c>-Kind-Tücke (siehe CLAUDE.md) und ist
|
|
/// direkt für Bereichs-Queries nutzbar.
|
|
/// </summary>
|
|
public class UntisAbsenceCacheEntry
|
|
{
|
|
public Guid Id { get; set; } = Guid.NewGuid();
|
|
public string ClassName { get; set; } = "";
|
|
public string StudentName { get; set; } = "";
|
|
public int? ExternKey { get; set; }
|
|
public int Date { get; set; }
|
|
public int AbsentPeriods { get; set; }
|
|
public int AbsentMinutes { get; set; }
|
|
public string? TeacherUsernames { get; set; }
|
|
public string? Subject { get; set; }
|
|
public string? AbsenceReason { get; set; }
|
|
public string? Note { get; set; }
|
|
public int? EntryId { get; set; }
|
|
public string? HandledOn { get; set; }
|
|
public bool Counts { get; set; }
|
|
public string? ExcuseNote { get; set; }
|
|
public int? PeriodNumber { get; set; }
|
|
public string? Status { get; set; }
|
|
public bool CountsAsFullDay { get; set; }
|
|
}
|
|
|
|
/// <summary>Lokal zwischengespeicherte Zeile aus dem "-alle-"-Klassenbuchbericht, gefiltert auf
|
|
/// Einträge anderer Lehrkräfte (Klassenlehrer-Feature) — 1:1-Abbildung von
|
|
/// `UntisForeignClassRegisterEventDto` (LehrerApp.Desktop).</summary>
|
|
public class UntisClassRegisterCacheEntry
|
|
{
|
|
public Guid Id { get; set; } = Guid.NewGuid();
|
|
public string ClassName { get; set; } = "";
|
|
public int Date { get; set; }
|
|
public string? Subject { get; set; }
|
|
public string StudentName { get; set; } = "";
|
|
public string? TeacherUsername { get; set; }
|
|
public string? CategoryName { get; set; }
|
|
public string? CategoryGroup { get; set; }
|
|
public string? Text { get; set; }
|
|
}
|
|
|
|
/// <summary>Lokal zwischengespeicherte Zeile aus dem WebUntis-Schülerreport, eingeschränkt auf die
|
|
/// für die Klassenlehrer-Übersicht nötigen Felder (Roster-Namen) — anders als Fehlzeiten/
|
|
/// Klassenbuch keine Historie, sondern immer nur der zuletzt abgerufene Stand einer Klasse
|
|
/// (siehe <see cref="UntisClassRegisterCacheEntry"/> für den Grund, warum es trotzdem ein eigenes
|
|
/// Modell statt Wiederverwendung des vollen Schülerreport-DTOs ist: nur diese zwei Felder werden
|
|
/// für den Roster-Abgleich tatsächlich gebraucht).</summary>
|
|
public class UntisStudentRosterCacheEntry
|
|
{
|
|
public Guid Id { get; set; } = Guid.NewGuid();
|
|
public string ClassName { get; set; } = "";
|
|
public int? ExternKey { get; set; }
|
|
public string DisplayName { get; set; } = "";
|
|
}
|
|
|
|
public enum UntisCacheKind { Absences, ClassRegister, Roster }
|
|
|
|
/// <summary>
|
|
/// Ein Datensatz pro (<see cref="ClassName"/>, <see cref="Kind"/>): wann das "heiße" Fenster
|
|
/// (die letzten Tage, deren Status sich noch ändern kann) zuletzt aufgefrischt wurde, und wie weit
|
|
/// die "kalte", als endgültig angenommene Historie bereits lückenlos zurückreicht. Getrennt von den
|
|
/// Cache-Zeilen selbst, weil ein Fenster ohne Treffer (z.B. eine ereignislose Woche) sonst keine
|
|
/// Zeile hinterließe, aus der sich "zuletzt abgerufen am…" ableiten ließe.
|
|
/// </summary>
|
|
public class UntisCacheFetchState
|
|
{
|
|
public Guid Id { get; set; } = Guid.NewGuid();
|
|
public string ClassName { get; set; } = "";
|
|
public UntisCacheKind Kind { get; set; }
|
|
public DateTime? HotWindowFetchedAt { get; set; }
|
|
public int? ColdCoverageStartDate { get; set; }
|
|
}
|