Wetterdienst

This commit is contained in:
2026-08-23 20:51:19 +02:00
parent cc973418f3
commit 1b32166ce0
21 changed files with 1186 additions and 3 deletions
@@ -0,0 +1,73 @@
using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using LehrerApp.Core.Models;
namespace LehrerApp.Desktop.Services;
public sealed class SchoolWeatherException(string message) : Exception(message);
/// <summary>Client für das serverseitige Schulstandort-/Wetterprofil. Liest URL und Token je
/// Aufruf, damit ein Login oder Serverwechsel in den Einstellungen sofort berücksichtigt wird.</summary>
public sealed class SchoolWeatherService(HttpClient http, SyncSettingsService syncSettings)
{
public bool IsAvailable => !string.IsNullOrWhiteSpace(syncSettings.ServerUrl) && syncSettings.IsLoggedIn;
public async Task<SchoolLocationProfile?> GetLocationAsync(CancellationToken cancellationToken = default)
{
using var response = await SendAsync(HttpMethod.Get, "/api/school/location", null, cancellationToken);
if (response.StatusCode == HttpStatusCode.NotFound) return null;
await EnsureSuccessAsync(response);
return await response.Content.ReadFromJsonAsync<SchoolLocationProfile>(cancellationToken);
}
public async Task<SchoolLocationProfile> SaveLocationAsync(SchoolLocationRequest location,
CancellationToken cancellationToken = default)
{
using var response = await SendAsync(HttpMethod.Put, "/api/school/location", location, cancellationToken);
await EnsureSuccessAsync(response);
return await response.Content.ReadFromJsonAsync<SchoolLocationProfile>(cancellationToken)
?? throw new SchoolWeatherException("Der Server hat keine Standortdaten zurückgegeben.");
}
public async Task<WeatherSnapshot?> GetWeatherAsync(CancellationToken cancellationToken = default)
{
using var response = await SendAsync(HttpMethod.Get, "/api/school/weather", null, cancellationToken);
if (response.StatusCode == HttpStatusCode.NotFound) return null;
await EnsureSuccessAsync(response);
return await response.Content.ReadFromJsonAsync<WeatherSnapshot>(cancellationToken);
}
private async Task<HttpResponseMessage> SendAsync(HttpMethod method, string path, object? body,
CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(syncSettings.ServerUrl) || !syncSettings.IsLoggedIn)
throw new SchoolWeatherException("Bitte zuerst im Reiter „Synchronisation“ am Server anmelden.");
using var request = new HttpRequestMessage(method, new Uri(new Uri(syncSettings.ServerUrl), path));
var token = syncSettings.GetToken();
if (token is not null)
request.Headers.Authorization = new("Bearer", token);
if (body is not null) request.Content = JsonContent.Create(body);
try { return await http.SendAsync(request, cancellationToken); }
catch (HttpRequestException)
{
throw new SchoolWeatherException("Der LehrerApp-Server ist nicht erreichbar.");
}
}
private static async Task EnsureSuccessAsync(HttpResponseMessage response)
{
if (response.IsSuccessStatusCode) return;
if (response.StatusCode == HttpStatusCode.Unauthorized)
throw new SchoolWeatherException("Die Server-Anmeldung ist abgelaufen. Bitte erneut anmelden.");
try
{
using var document = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
if (document.RootElement.TryGetProperty("detail", out var detail) &&
!string.IsNullOrWhiteSpace(detail.GetString()))
throw new SchoolWeatherException(detail.GetString()!);
}
catch (JsonException) { }
throw new SchoolWeatherException("Der Schulstandort konnte nicht gespeichert werden.");
}
}