Untis API Integration
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace LehrerApp.Api;
|
||||
|
||||
public sealed record WebUntisConnectRequest(
|
||||
string School,
|
||||
string? Host,
|
||||
string Username,
|
||||
string Password);
|
||||
|
||||
public sealed record WebUntisConnectionStatus(bool Connected, string? School, string? Username);
|
||||
|
||||
/// <summary>
|
||||
/// Hält persönliche WebUntis-Verbindungen ausschließlich im Arbeitsspeicher des Servers.
|
||||
/// Passwörter werden weder protokolliert noch serverseitig persistiert. Der enthaltene Client
|
||||
/// verwaltet die eigentliche WebUntis-Session und meldet sie nach Inaktivität wieder ab.
|
||||
/// </summary>
|
||||
public sealed class WebUntisConnectionStore(IHttpClientFactory httpClientFactory) : IAsyncDisposable
|
||||
{
|
||||
private sealed record Entry(WebUntisClient Client, string School, string Username);
|
||||
|
||||
private readonly ConcurrentDictionary<string, Entry> _connections = new();
|
||||
|
||||
public WebUntisClient? GetClient(string userId) =>
|
||||
_connections.TryGetValue(userId, out var entry) ? entry.Client : null;
|
||||
|
||||
public WebUntisConnectionStatus GetStatus(string userId) =>
|
||||
_connections.TryGetValue(userId, out var entry)
|
||||
? new(true, entry.School, entry.Username)
|
||||
: new(false, null, null);
|
||||
|
||||
public async Task<WebUntisConnectionStatus> ConnectAsync(string userId, WebUntisConnectRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var options = new WebUntisOptions
|
||||
{
|
||||
School = request.School,
|
||||
Host = request.Host ?? "",
|
||||
Username = request.Username,
|
||||
Password = request.Password,
|
||||
Client = "LehrerApp",
|
||||
SessionIdleTimeoutMinutes = 10,
|
||||
};
|
||||
var client = new WebUntisClient(httpClientFactory.CreateClient("webuntis"), Options.Create(options));
|
||||
try
|
||||
{
|
||||
// Authentifiziert wirklich gegen WebUntis; ungültige Daten werden nicht gespeichert.
|
||||
await client.GetSchoolYearsAsync(cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await client.DisposeAsync();
|
||||
throw;
|
||||
}
|
||||
|
||||
var entry = new Entry(client, request.School.Trim(), request.Username.Trim());
|
||||
if (_connections.TryGetValue(userId, out var previous))
|
||||
await previous.Client.DisposeAsync();
|
||||
_connections[userId] = entry;
|
||||
return new(true, entry.School, entry.Username);
|
||||
}
|
||||
|
||||
public async Task DisconnectAsync(string userId)
|
||||
{
|
||||
if (_connections.TryRemove(userId, out var entry)) await entry.Client.DisposeAsync();
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
var entries = _connections.Values.ToList();
|
||||
_connections.Clear();
|
||||
foreach (var entry in entries) await entry.Client.DisposeAsync();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user