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:
2026-08-23 13:30:15 +02:00
co-authored by Claude Sonnet 5
parent e65a729f97
commit 4eb4d0a946
30 changed files with 3333 additions and 8 deletions
+73
View File
@@ -955,6 +955,79 @@ public sealed class RepositoryTests
Assert.Equal("Vertretung 8a", result[0].Description);
}
[Fact]
public void SubstitutionEntryRepository_GetByExternalId_FindetAutomatischErzeugtenEintrag()
{
using var db = NewInMemoryContext();
var repo = new SubstitutionEntryRepository(db);
repo.Save(new SubstitutionEntry { Date = new DateOnly(2026, 3, 12), Kind = SubstitutionKind.Cancelled, PeriodNumber = 3, ExternalId = "38818-2004584-2004587" });
repo.Save(new SubstitutionEntry { Date = new DateOnly(2026, 3, 13), Kind = SubstitutionKind.Cancelled, PeriodNumber = 4 });
var result = repo.GetByExternalId("38818-2004584-2004587");
Assert.NotNull(result);
Assert.Equal(new DateOnly(2026, 3, 12), result!.Date);
Assert.Null(repo.GetByExternalId("unbekannt"));
}
// ── UntisSnapshotRepository / UntisSlotMappingRepository ─────────────────
[Fact]
public void UntisSnapshotRepository_SaveUndGetAll_RoundTrip()
{
using var db = NewInMemoryContext();
var repo = new UntisSnapshotRepository(db);
repo.Save(new UntisSnapshotEntry
{
Uid = "38926-2013812-2013815", Date = new DateOnly(2026, 8, 17),
StartTime = new TimeOnly(7, 50), EndTime = new TimeOnly(9, 20),
Summary = "SOL", Location = "Medien", Description = "10c HED",
});
var result = repo.GetAll();
Assert.Single(result);
Assert.Equal("38926-2013812-2013815", result[0].Uid);
Assert.Equal("SOL", result[0].Summary);
}
[Fact]
public void UntisSnapshotRepository_Save_AktualisiertVorhandenenEintrag()
{
using var db = NewInMemoryContext();
var repo = new UntisSnapshotRepository(db);
var entry = new UntisSnapshotEntry { Uid = "38926-2013812-2013815", Location = "Medien" };
repo.Save(entry);
entry.Location = "A1";
entry.Status = "CANCELLED";
repo.Save(entry);
var result = Assert.Single(repo.GetAll());
Assert.Equal("A1", result.Location);
Assert.Equal("CANCELLED", result.Status);
}
[Fact]
public void UntisSlotMappingRepository_SaveDeleteUndGetAll_RoundTrip()
{
using var db = NewInMemoryContext();
var repo = new UntisSlotMappingRepository(db);
var groupId = Guid.NewGuid();
var mapping = new UntisSlotMapping
{
Weekday = DayOfWeek.Monday, StartTime = new TimeOnly(7, 50),
Summary = "SOL", ClassToken = "10c", GroupId = groupId, Confirmed = true,
};
repo.Save(mapping);
Assert.Single(repo.GetAll());
repo.Delete(mapping.Id);
Assert.Empty(repo.GetAll());
}
// ── WorkTaskRepository ────────────────────────────────────────────────────
[Fact]