fix: connection leak in UpsertDiscordUserAsync + false conflict in LinkIdentityAsync
PR Checks / test-and-build (pull_request) Successful in 7m25s
PR Checks / test-and-build (pull_request) Successful in 7m25s
- UpsertDiscordUserAsync: restore await using on opened connection - LinkIdentityAsync: compute effectiveCurrentPrimary before existingLink check to prevent false conflict when current user is a secondary identity Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1412,6 +1412,17 @@ public sealed class SessionService(
|
|||||||
throw new InvalidOperationException("Target identity is already the primary account of another linked set.");
|
throw new InvalidOperationException("Target identity is already the primary account of another linked set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if current is already a secondary (then their primary becomes the effective primary)
|
||||||
|
var currentPrimaryId = await conn.QuerySingleOrDefaultAsync<Guid?>(
|
||||||
|
"""
|
||||||
|
SELECT primary_player_id
|
||||||
|
FROM player_links
|
||||||
|
WHERE secondary_player_id = @CurrentPlayerId
|
||||||
|
""",
|
||||||
|
new { CurrentPlayerId = currentPlayerId.Value }, transaction);
|
||||||
|
|
||||||
|
var effectiveCurrentPrimary = currentPrimaryId ?? currentPlayerId.Value;
|
||||||
|
|
||||||
// Check if target is already linked to someone else as secondary
|
// Check if target is already linked to someone else as secondary
|
||||||
var existingLink = await conn.QuerySingleOrDefaultAsync<Guid?>(
|
var existingLink = await conn.QuerySingleOrDefaultAsync<Guid?>(
|
||||||
"""
|
"""
|
||||||
@@ -1421,23 +1432,14 @@ public sealed class SessionService(
|
|||||||
""",
|
""",
|
||||||
new { TargetPlayerId = targetPlayerId }, transaction);
|
new { TargetPlayerId = targetPlayerId }, transaction);
|
||||||
|
|
||||||
if (existingLink is not null && existingLink.Value != currentPlayerId.Value)
|
if (existingLink is not null && existingLink.Value != effectiveCurrentPrimary)
|
||||||
{
|
{
|
||||||
await _LogIdentityAuditAsync(conn, currentPlayerId.Value, "link_attempt_conflict",
|
await _LogIdentityAuditAsync(conn, effectiveCurrentPrimary, "link_attempt_conflict",
|
||||||
targetPlatform, targetExternalUserId, currentPlayerId.Value, transaction);
|
targetPlatform, targetExternalUserId, currentPlayerId.Value, transaction);
|
||||||
await transaction.CommitAsync();
|
await transaction.CommitAsync();
|
||||||
throw new InvalidOperationException("Target identity is already linked to another account.");
|
throw new InvalidOperationException("Target identity is already linked to another account.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if current is already a secondary (then their primary becomes the effective primary)
|
|
||||||
var currentPrimaryId = await conn.QuerySingleOrDefaultAsync<Guid?>(
|
|
||||||
"""
|
|
||||||
SELECT primary_player_id
|
|
||||||
FROM player_links
|
|
||||||
WHERE secondary_player_id = @CurrentPlayerId
|
|
||||||
""",
|
|
||||||
new { CurrentPlayerId = currentPlayerId.Value }, transaction);
|
|
||||||
|
|
||||||
var effectivePrimary = currentPrimaryId ?? currentPlayerId.Value;
|
var effectivePrimary = currentPrimaryId ?? currentPlayerId.Value;
|
||||||
|
|
||||||
// Check if already linked
|
// Check if already linked
|
||||||
@@ -1527,7 +1529,8 @@ public sealed class SessionService(
|
|||||||
|
|
||||||
public async Task UpsertDiscordUserAsync(string discordId, string displayName, string? avatarUrl)
|
public async Task UpsertDiscordUserAsync(string discordId, string displayName, string? avatarUrl)
|
||||||
{
|
{
|
||||||
await _UpsertPlayerAndGetIdAsync(await dataSource.OpenConnectionAsync(), "Discord", discordId, displayName, avatarUrl, null);
|
await using var conn = await dataSource.OpenConnectionAsync();
|
||||||
|
await _UpsertPlayerAndGetIdAsync(conn, "Discord", discordId, displayName, avatarUrl, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Private helpers ---
|
// --- Private helpers ---
|
||||||
|
|||||||
Reference in New Issue
Block a user