fix(web): add public-session guards and ON CONFLICT to RegisterFromShowcaseAsync

This commit is contained in:
2026-05-28 15:40:21 +03:00
parent b2497ed877
commit a5f4a68c6a
+28 -34
View File
@@ -541,12 +541,18 @@ public sealed class SessionService(
var session = await conn.QuerySingleOrDefaultAsync<dynamic>( var session = await conn.QuerySingleOrDefaultAsync<dynamic>(
""" """
SELECT id, max_players AS MaxPlayers, allow_direct_registration AS AllowDirectRegistration SELECT s.id, s.max_players AS MaxPlayers, s.allow_direct_registration AS AllowDirectRegistration
FROM sessions FROM sessions s
WHERE id = @SessionId JOIN game_groups g ON g.id = s.group_id
FOR UPDATE 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); transaction);
if (session is null || !(bool)session.allowdirectregistration) 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 playerId = await _UpsertPlayerAndGetIdAsync(conn, platform, externalUserId, displayName, null, transaction);
var existing = await conn.ExecuteScalarAsync<bool>( var registrationStatus = SessionCapacityRules.DecideJoinStatus(
""" (int?)session.maxplayers,
SELECT EXISTS ( await conn.ExecuteScalarAsync<int>(
SELECT 1 FROM session_participants """
WHERE session_id = @SessionId AND player_id = @PlayerId SELECT COUNT(*) FROM session_participants
) WHERE session_id = @SessionId AND is_gm = false AND registration_status = @Active
""", """,
new { SessionId = sessionId, PlayerId = playerId }, new { SessionId = sessionId, Active = ParticipantRegistrationStatus.Active },
transaction); transaction));
if (existing) var inserted = await conn.ExecuteAsync(
{
await transaction.RollbackAsync();
return false;
}
var activeCount = await conn.ExecuteScalarAsync<int>(
"""
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(
""" """
INSERT INTO session_participants (session_id, player_id, is_gm, rsvp_status, registration_status) INSERT INTO session_participants (session_id, player_id, is_gm, rsvp_status, registration_status)
VALUES (@SessionId, @PlayerId, false, @Pending, @RegistrationStatus) VALUES (@SessionId, @PlayerId, false, @Pending, @RegistrationStatus)
ON CONFLICT (session_id, player_id) DO NOTHING
""", """,
new new
{ {
@@ -600,6 +588,12 @@ public sealed class SessionService(
}, },
transaction); transaction);
if (inserted == 0)
{
await transaction.RollbackAsync();
return false;
}
await transaction.CommitAsync(); await transaction.CommitAsync();
return true; return true;
} }