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:
@@ -0,0 +1,93 @@
|
||||
using LehrerApp.Sync.Crypto;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace LehrerApp.Desktop.Services;
|
||||
|
||||
internal class WebUntisSettingsConfig
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public string? EncryptedIcalUrl { get; set; }
|
||||
public DateTime? LastSyncAt { get; set; }
|
||||
public string LastSyncStatus { get; set; } = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Einstellungen für den WebUntis-iCal-Abgleich (Nutzer-Feedback, siehe TODO.md). Liegt wie
|
||||
/// AiSettingsService/SyncSettingsService in LehrerApp.Desktop statt LehrerApp.Core, da die
|
||||
/// Verschlüsselung über <see cref="SyncCrypto"/> aus LehrerApp.Sync läuft — Core bleibt bewusst
|
||||
/// frei von Abhängigkeiten außerhalb von .NET selbst (siehe CLAUDE.md).
|
||||
///
|
||||
/// Die iCal-URL trägt ein eingebettetes Auth-Token und wird deshalb wie ein Passwort behandelt:
|
||||
/// nie im Klartext persistiert, nur AES-256-GCM-verschlüsselt (gleicher Mechanismus wie beim
|
||||
/// KI-Backend-Token) mit einem eigenen, dateirechte-geschützten Schlüssel.
|
||||
/// </summary>
|
||||
public class WebUntisSettingsService
|
||||
{
|
||||
private readonly string _configPath;
|
||||
private readonly string _keyPath;
|
||||
private readonly byte[] _urlKey;
|
||||
private WebUntisSettingsConfig _config;
|
||||
|
||||
public bool Enabled => _config.Enabled;
|
||||
public bool IsConfigured => _config.EncryptedIcalUrl is not null;
|
||||
public DateTime? LastSyncAt => _config.LastSyncAt;
|
||||
public string LastSyncStatus => _config.LastSyncStatus;
|
||||
|
||||
public WebUntisSettingsService(string appDataPath)
|
||||
{
|
||||
_configPath = Path.Combine(appDataPath, "webuntis-settings.json");
|
||||
_keyPath = Path.Combine(appDataPath, "webuntis-url.key");
|
||||
_urlKey = SyncCrypto.LoadKey(_keyPath) ?? GenerateAndSaveKey();
|
||||
_config = Load();
|
||||
}
|
||||
|
||||
public void SetEnabled(bool enabled)
|
||||
{
|
||||
_config.Enabled = enabled;
|
||||
Save();
|
||||
}
|
||||
|
||||
public void SetIcalUrl(string url)
|
||||
{
|
||||
_config.EncryptedIcalUrl = SyncCrypto.EncryptObject(url, _urlKey);
|
||||
Save();
|
||||
}
|
||||
|
||||
public string? GetIcalUrl() =>
|
||||
_config.EncryptedIcalUrl is null ? null : SyncCrypto.DecryptObject<string>(_config.EncryptedIcalUrl, _urlKey);
|
||||
|
||||
public void ClearIcalUrl()
|
||||
{
|
||||
_config.EncryptedIcalUrl = null;
|
||||
_config.Enabled = false;
|
||||
Save();
|
||||
}
|
||||
|
||||
public void SetLastSync(DateTime at, string status)
|
||||
{
|
||||
_config.LastSyncAt = at;
|
||||
_config.LastSyncStatus = status;
|
||||
Save();
|
||||
}
|
||||
|
||||
private byte[] GenerateAndSaveKey()
|
||||
{
|
||||
var key = SyncCrypto.GenerateKey();
|
||||
SyncCrypto.SaveKey(key, _keyPath);
|
||||
return key;
|
||||
}
|
||||
|
||||
private void Save() => File.WriteAllText(_configPath, JsonSerializer.Serialize(_config));
|
||||
|
||||
private WebUntisSettingsConfig Load()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(_configPath))
|
||||
return JsonSerializer.Deserialize<WebUntisSettingsConfig>(File.ReadAllText(_configPath))
|
||||
?? new WebUntisSettingsConfig();
|
||||
}
|
||||
catch { /* beschädigte Konfiguration -> Standardwert */ }
|
||||
return new WebUntisSettingsConfig();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user