Some checks failed
Build / build (pull_request) Has been cancelled
Doku/Repo: - README.md mit Setup, Run-Anleitung, Konfiguration und Sprachpolicy neu geschrieben - appsettings.json: committed JWT-Key und irreführende LocalDB-Connection-String entfernt - appsettings.Development.json: expliziter Dev-Only JWT-Key hinterlegt - build.yml: Build-CI für master/PRs hinzugefügt - slnx/aspire.config.json: Pfad-Casing korrigiert (Linux-kompatibel) - .gitignore: Kommentar zu den Legacy-SQLite-Einträgen Server: - Jwt:Key ist in Production Pflicht (Fail-fast statt Fallback-Secret) - Passwort-Mindestlänge 8 Zeichen bei Registrierung - StartGame: nur aus Lobby, mindestens 2 Spieler - SetPlayerReady: gameId/Status geprüft - SubmitSlip: Game-/Round-Status, Round-Membership, IsUsed validiert - CreateChallenge: Round-Bindung, kein Self-Challenge, nur gespielte Karten, keine Doppel-Challenges - ResolveChallenge: Pending-Guard, Scoring (Score/SuccessfulSlips/FailedSlips), Approved-Transfer gefixt - GetPlayerHand: nur Karten der aktiven Runde - RoundTimeRemaining: StartedAt wird bei Round-Aktivierung gesetzt - Lobby-Code: crypto-random mit Kollisions-Retry - EF: explizite NpgsqlDataSource-Auflösung aus DI - Hub: Reconnect-Gruppenbeitritt, ConnectionId-Cleanup beim Disconnect, ChallengingPlayerName gesetzt, SlipChallenged/ChallengeResolved konsistent Client: - Offline-Start löscht Session nicht mehr (NetworkError vs. Invalid unterschieden) - ResolveChallenge geht durch die Offline-Queue (kein Crash mehr bei Disconnect) - Queue: Poison-Entries werden nach 3 Retries verworfen statt die Queue ewig zu blockieren - SignalR: Verbindung wird sauber disposed/rebuildet, Token immer zur Laufzeit gelesen, Connect-Lock gegen parallele Starts - ViewModels: Thread-Marshaling in allen Receive-Handlern, kein async void mehr - LobbyViewModel: Logout deaktiviert den Singleton (kein stale-Navigation mehr), Reaktivierung via Activate() - GameBoard: lokaler 1s-Timer für RoundTimeRemaining - Overlay: x:DataType für kompilierte Bindings, Frame→Border - csproj: Preview-Logging-Package auf 10.0.10, Template-Cruft entfernt
82 lines
2.5 KiB
C#
82 lines
2.5 KiB
C#
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using CommunityToolkit.Mvvm.Input;
|
|
using SlipItIn.Services.Interfaces;
|
|
using SlipItIn.Shared.DTOs;
|
|
using SlipItIn.Views;
|
|
|
|
namespace SlipItIn.ViewModels;
|
|
|
|
public partial class LoginViewModel : BaseViewModel
|
|
{
|
|
private readonly IApiService _apiService;
|
|
private readonly IAuthSessionService _authSession;
|
|
private readonly ISignalRService _signalR;
|
|
private readonly IGameStateService _gameStateService;
|
|
|
|
[ObservableProperty]
|
|
private string email = string.Empty;
|
|
|
|
[ObservableProperty]
|
|
private string password = string.Empty;
|
|
|
|
public LoginViewModel(IApiService apiService, IAuthSessionService authSession, ISignalRService signalR, IGameStateService gameStateService)
|
|
{
|
|
_apiService = apiService;
|
|
_authSession = authSession;
|
|
_signalR = signalR;
|
|
_gameStateService = gameStateService;
|
|
}
|
|
|
|
[RelayCommand]
|
|
private Task GoToRegisterAsync() => Shell.Current.GoToAsync(nameof(RegisterPage));
|
|
|
|
[RelayCommand]
|
|
private async Task LoginAsync()
|
|
{
|
|
await RunSafeAsync(async () =>
|
|
{
|
|
var response = await _apiService.LoginAsync(new LoginRequestDto
|
|
{
|
|
Email = Email,
|
|
Password = Password
|
|
});
|
|
|
|
await _authSession.SetSessionAsync(response);
|
|
|
|
var connected = await _signalR.ConnectAsync(response.Token);
|
|
if (!connected)
|
|
throw new InvalidOperationException("Verbindung zum Spielserver fehlgeschlagen.");
|
|
|
|
await _gameStateService.InitializeAsync();
|
|
await Shell.Current.GoToAsync(nameof(LobbyPage));
|
|
}, "Anmeldung läuft...");
|
|
}
|
|
|
|
[RelayCommand]
|
|
public async Task InitializeAsync()
|
|
{
|
|
if (!_authSession.IsAuthenticated)
|
|
return;
|
|
|
|
var sessionResult = await _apiService.ValidateSessionAsync();
|
|
if (sessionResult == SessionValidationResult.NetworkError)
|
|
return;
|
|
|
|
if (sessionResult == SessionValidationResult.Invalid)
|
|
{
|
|
await _authSession.ClearSessionAsync();
|
|
await _gameStateService.ClearLocalGameDataAsync();
|
|
await _signalR.DisconnectAsync();
|
|
return;
|
|
}
|
|
|
|
var token = _authSession.AccessToken;
|
|
if (string.IsNullOrWhiteSpace(token))
|
|
return;
|
|
|
|
var connected = await _signalR.ConnectAsync(token);
|
|
if (connected)
|
|
await Shell.Current.GoToAsync(nameof(LobbyPage));
|
|
}
|
|
}
|