76 lines
3.5 KiB
C#
76 lines
3.5 KiB
C#
using System.Net;
|
|
using System.Net.Http.Json;
|
|
using LehrerApp.Sync;
|
|
|
|
namespace LehrerApp.Desktop.Services;
|
|
|
|
public class SyncAuthException(string userMessage) : Exception(userMessage);
|
|
|
|
public enum SyncConnectionTestResult { Ok, Unauthorized, IncompatibleVersion, Unreachable }
|
|
|
|
/// <summary>
|
|
/// Login/Verbindungstest gegen den eigenen Sync-Server (LehrerApp.Api) — getrennt vom bereits
|
|
/// bestehenden <see cref="AiPlanningService"/> (anderes Backend, anderer Wire-Vertrag). Nimmt die
|
|
/// Server-URL je Aufruf entgegen statt fest im Konstruktor, weil sie über die Einstellungen zur
|
|
/// Laufzeit geändert werden kann (anders als die feste KI-Backend-URL).
|
|
/// </summary>
|
|
public class SyncAuthService(HttpClient http)
|
|
{
|
|
/// <summary>
|
|
/// Liefert neben dem Token auch die kanonische userId aus der Server-Antwort - LiteDBs
|
|
/// case-insensitive Standard-Collation lässt einen Login mit abweichender
|
|
/// Groß-/Kleinschreibung des Benutzernamens erfolgreich durch (siehe TODO 10.2.5); die
|
|
/// zurückgegebene userId ist deshalb der einzige verlässliche Weg für den Aufrufer, einen
|
|
/// Kontowechsel von einer bloßen Schreibweisen-Abweichung zu unterscheiden (siehe TODO 10.3.5).
|
|
/// </summary>
|
|
public async Task<(string Token, string UserId)> LoginAsync(string serverUrl, string username, string password)
|
|
{
|
|
HttpResponseMessage resp;
|
|
try
|
|
{
|
|
using var req = SyncProtocol.CreateRequest(HttpMethod.Post,
|
|
CombineUrl(serverUrl, "/api/auth/login"));
|
|
req.Content = JsonContent.Create(new { username, password });
|
|
resp = await http.SendAsync(req);
|
|
}
|
|
catch (HttpRequestException)
|
|
{
|
|
throw new SyncAuthException(
|
|
"Der Sync-Server ist nicht erreichbar. Bitte Adresse und Internetverbindung prüfen.");
|
|
}
|
|
|
|
if (resp.StatusCode == HttpStatusCode.Unauthorized)
|
|
throw new SyncAuthException("Benutzername oder Passwort ist falsch.");
|
|
if (!resp.IsSuccessStatusCode)
|
|
throw new SyncAuthException("Anmeldung fehlgeschlagen. Bitte später erneut versuchen.");
|
|
|
|
var result = await resp.Content.ReadFromJsonAsync<LoginResult>();
|
|
return result is null
|
|
? throw new SyncAuthException("Unerwartete Antwort des Sync-Servers.")
|
|
: (result.Token, result.UserId);
|
|
}
|
|
|
|
public async Task<SyncConnectionTestResult> TestConnectionAsync(string serverUrl, string? token)
|
|
{
|
|
using var req = new HttpRequestMessage(HttpMethod.Get, CombineUrl(serverUrl, "/api/sync/status"));
|
|
req.Headers.Add(SyncProtocol.VersionHeaderName, SyncProtocol.CurrentVersion);
|
|
if (token is not null)
|
|
req.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
|
|
|
|
try
|
|
{
|
|
var resp = await http.SendAsync(req);
|
|
if (resp.StatusCode == HttpStatusCode.Unauthorized) return SyncConnectionTestResult.Unauthorized;
|
|
if (resp.StatusCode == HttpStatusCode.UpgradeRequired)
|
|
return SyncConnectionTestResult.IncompatibleVersion;
|
|
return resp.IsSuccessStatusCode ? SyncConnectionTestResult.Ok : SyncConnectionTestResult.Unreachable;
|
|
}
|
|
catch (HttpRequestException) { return SyncConnectionTestResult.Unreachable; }
|
|
}
|
|
|
|
private static string CombineUrl(string serverUrl, string path) =>
|
|
new Uri(new Uri(serverUrl), path).ToString();
|
|
|
|
private record LoginResult(string Token, string UserId);
|
|
}
|