diff --git a/src/GmRelay.Web/Services/SessionService.cs b/src/GmRelay.Web/Services/SessionService.cs index 158fc59..815512f 100644 --- a/src/GmRelay.Web/Services/SessionService.cs +++ b/src/GmRelay.Web/Services/SessionService.cs @@ -541,12 +541,18 @@ public sealed class SessionService( var session = await conn.QuerySingleOrDefaultAsync( """ - SELECT id, max_players AS MaxPlayers, allow_direct_registration AS AllowDirectRegistration - FROM sessions - WHERE id = @SessionId - FOR UPDATE + SELECT s.id, s.max_players AS MaxPlayers, s.allow_direct_registration AS AllowDirectRegistration + FROM sessions s + JOIN game_groups g ON g.id = s.group_id + WHERE s.id = @SessionId + AND s.is_public = true + AND g.public_schedule_enabled = true + AND g.public_slug IS NOT NULL + AND s.scheduled_at > now() - interval '4 hours' + AND s.status <> @Cancelled + FOR UPDATE OF s """, - new { SessionId = sessionId }, + new { SessionId = sessionId, Cancelled = SessionStatus.Cancelled }, transaction); if (session is null || !(bool)session.allowdirectregistration) @@ -557,39 +563,21 @@ public sealed class SessionService( var playerId = await _UpsertPlayerAndGetIdAsync(conn, platform, externalUserId, displayName, null, transaction); - var existing = await conn.ExecuteScalarAsync( - """ - SELECT EXISTS ( - SELECT 1 FROM session_participants - WHERE session_id = @SessionId AND player_id = @PlayerId - ) - """, - new { SessionId = sessionId, PlayerId = playerId }, - transaction); + var registrationStatus = SessionCapacityRules.DecideJoinStatus( + (int?)session.maxplayers, + await conn.ExecuteScalarAsync( + """ + SELECT COUNT(*) FROM session_participants + WHERE session_id = @SessionId AND is_gm = false AND registration_status = @Active + """, + new { SessionId = sessionId, Active = ParticipantRegistrationStatus.Active }, + transaction)); - if (existing) - { - await transaction.RollbackAsync(); - return false; - } - - var activeCount = await conn.ExecuteScalarAsync( - """ - SELECT COUNT(*) - FROM session_participants - WHERE session_id = @SessionId - AND is_gm = false - AND registration_status = @Active - """, - new { SessionId = sessionId, Active = ParticipantRegistrationStatus.Active }, - transaction); - - var registrationStatus = SessionCapacityRules.DecideJoinStatus((int?)session.maxplayers, activeCount); - - await conn.ExecuteAsync( + var inserted = await conn.ExecuteAsync( """ INSERT INTO session_participants (session_id, player_id, is_gm, rsvp_status, registration_status) VALUES (@SessionId, @PlayerId, false, @Pending, @RegistrationStatus) + ON CONFLICT (session_id, player_id) DO NOTHING """, new { @@ -600,6 +588,12 @@ public sealed class SessionService( }, transaction); + if (inserted == 0) + { + await transaction.RollbackAsync(); + return false; + } + await transaction.CommitAsync(); return true; }