WIP (unstable): WebUntis-iCal-Abgleich für Vertretungen/Ausfälle
Erkennt Vertretungen, Ausfälle und Zusatzaufsichten aus dem persönlichen WebUntis-iCal-Feed und schreibt sie automatisch als SubstitutionEntry. Bekannter offener Bug: es tauchen weiterhin falsche Vertretungen für Stunden auf, die real unverändert sind — wird in einem Folge-Commit untersucht, deshalb vorerst auf diesem Branch statt main. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -210,6 +210,12 @@ public class SubstitutionEntry
|
||||
/// Bezeichnung (bei SpecialAssignment, z.B. "Ausflug ins Museum", "Berufsmesse").
|
||||
public string Description { get; set; } = "";
|
||||
public string? Notes { get; set; }
|
||||
/// Gesetzt, wenn dieser Eintrag automatisch aus dem WebUntis-iCal-Abgleich entstanden ist —
|
||||
/// trägt die stabile iCal-UID des auslösenden Termins. Macht wiederholte Abgleich-Läufe
|
||||
/// idempotent (Update statt Duplikat, siehe ISubstitutionEntryRepository.GetByExternalId) und
|
||||
/// unterscheidet automatisch erzeugte von von Hand eingetragenen Ausnahmen. Bei Handeinträgen
|
||||
/// (SubstitutionEntryDialogViewModel) bleibt es null.
|
||||
public string? ExternalId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
namespace LehrerApp.Core.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Zuletzt bekannter Zustand eines einzelnen WebUntis-iCal-Termins (ein VEVENT) — die lokale
|
||||
/// "Sicherungskopie", gegen die jeder neue Abruf verglichen wird, um Änderungen zu erkennen
|
||||
/// (Nutzer-Feedback: "Abgleich mit einem lokalen Backup, um Änderungen zu finden"). <see cref="Uid"/>
|
||||
/// ist die stabile iCal-UID des Termins (pro Wochen-Slot über das ganze Schuljahr gleich) und
|
||||
/// dient als fachlicher Schlüssel für den Abgleich — bewusst kein <c>[BsonId]</c> darauf, da
|
||||
/// LehrerApp.Core absichtlich frei von LiteDB/Avalonia-Abhängigkeiten bleibt (siehe CLAUDE.md);
|
||||
/// die Suche nach <see cref="Uid"/> läuft stattdessen über eine gefilterte Repository-Abfrage.
|
||||
/// </summary>
|
||||
public class UntisSnapshotEntry
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
public string Uid { get; set; } = "";
|
||||
public DateOnly Date { get; set; }
|
||||
public TimeOnly StartTime { get; set; }
|
||||
public TimeOnly EndTime { get; set; }
|
||||
public string? Summary { get; set; }
|
||||
public string Location { get; set; } = "";
|
||||
public string Description { get; set; } = "";
|
||||
public string Status { get; set; } = "CONFIRMED";
|
||||
public DateTime LastSeenAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Vom Nutzer bestätigte Zuordnung eines regulären WebUntis-Wochenmusters (Wochentag + Uhrzeit +
|
||||
/// Fach-Kürzel + Klassen-Token aus der Beschreibung) zu einer bestehenden <see cref="LearningGroup"/>
|
||||
/// (<see cref="SubstitutionKind.Lesson"/>) oder — für Termine ohne Klassenbezug, z.B. Aufsichten —
|
||||
/// zu einer festen Pause (<see cref="SubstitutionKind.Supervision"/>, <see cref="AfterPeriod"/>
|
||||
/// statt <see cref="GroupId"/>/<see cref="PeriodNumber"/>; Nutzer-Feedback: "Zwei Termine sind
|
||||
/// meine Aufsichten, die nicht zugeordnet werden können [...] vom Zeitraster und von der Dauer her
|
||||
/// könnten die erfasst werden" — Aufsichten liegen in Pausen, nicht auf einem Unterrichtsstunden-
|
||||
/// Zeitraster, brauchen also einen eigenen Auflösungsweg statt PeriodNumber). Nur bestätigte
|
||||
/// (<see cref="Confirmed"/> true) Zuordnungen lösen automatisch geschriebene
|
||||
/// <see cref="SubstitutionEntry"/>-Einträge aus (Nutzer-Feedback: die erstmalige Zuordnung ist
|
||||
/// fehleranfällig — falsche Gruppe würde falsche Vertretungen erzeugen — und braucht deshalb eine
|
||||
/// Bestätigung, bevor sie aktiv wird; siehe UntisMappingReviewDialog).
|
||||
/// </summary>
|
||||
public class UntisSlotMapping
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
public DayOfWeek Weekday { get; set; }
|
||||
public TimeOnly StartTime { get; set; }
|
||||
public string? Summary { get; set; }
|
||||
public string ClassToken { get; set; } = "";
|
||||
public SubstitutionKind Kind { get; set; } = SubstitutionKind.Lesson;
|
||||
/// Nur bei <see cref="SubstitutionKind.Lesson"/> gesetzt.
|
||||
public Guid? GroupId { get; set; }
|
||||
/// Erste/primäre Stunde, zum Bestätigungszeitpunkt über PeriodScheduleService aufgelöst (siehe
|
||||
/// UntisMatchingService) — hier gespeichert, damit UntisDiffService selbst framework-frei
|
||||
/// bleibt und keine eigene Uhrzeit→Stunde-Auflösung braucht. Nur bei
|
||||
/// <see cref="SubstitutionKind.Lesson"/> gesetzt.
|
||||
public int? PeriodNumber { get; set; }
|
||||
/// ALLE Stunden, die dieser WebUntis-Termin überdeckt (siehe UntisSlotMatch.CoveredPeriods) —
|
||||
/// bei einer Doppelstunde mehr als eine. Entscheidet, welche TimetableSlots als "durch WebUntis
|
||||
/// bestätigt" gelten (Nutzer-Feedback: "ich habe aber jetzt alles zugeordnet, und trotzdem
|
||||
/// erhalte ich die Warnung, dass 16 Stunden ohne Untis-Zuordnung sind" — ohne diese Liste blieb
|
||||
/// die zweite Stunde einer Doppelstunde immer "unzugeordnet", weil WebUntis dafür nur einen
|
||||
/// einzigen, am Anfang beginnenden Termin meldet). Nur bei <see cref="SubstitutionKind.Lesson"/>
|
||||
/// gesetzt.
|
||||
public List<int> CoveredPeriods { get; set; } = [];
|
||||
/// Nur bei <see cref="SubstitutionKind.Supervision"/> gesetzt — wie bei
|
||||
/// <see cref="SupervisionDuty.AfterPeriod"/>, ebenfalls zum Bestätigungszeitpunkt aufgelöst
|
||||
/// (die Pause direkt vor der WebUntis-Startzeit, 0 = vor der 1. Stunde).
|
||||
public int? AfterPeriod { get; set; }
|
||||
public bool Confirmed { get; set; }
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
Reference in New Issue
Block a user