refactor: завершить platform migration и удалить deprecated telegram_* scaffolding
PR Checks / test-and-build (pull_request) Failing after 13m15s

- Добавлены миграции V024 (backfill + deprecation comments + calendar_subscriptions platform identity) и V025 (backfill proposed_by_external_user_id)
- Все Bot handlers переведены с telegram_id/chat_id на platform + external_*
- Shared handlers очищены от COALESCE fallback с telegram_* колонками
- DiscordBot очищен от COALESCE fallback
- Web SessionService и CalendarSubscriptionService переведены на external_*
- HandleRsvpHandler: убран legacy UNION с gm_telegram_id, теперь только group_managers
- RescheduleVotingFinalizer: переведен на external_username/external_user_id
- Tests: добавлены asserts для V024/V025
- Версия обновлена до 3.1.0

Bump version → 3.1.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 16:41:15 +03:00
parent a5aed14dd2
commit 040b0a3cdb
28 changed files with 228 additions and 156 deletions
@@ -77,16 +77,15 @@ public sealed class CreateSessionHandler(
{
await connection.ExecuteAsync(
"""
INSERT INTO players (telegram_id, display_name, telegram_username, platform, external_user_id, external_username)
VALUES (@TgId, @Name, @Username, 'Telegram', @TgId::TEXT, @Username)
ON CONFLICT (telegram_id) DO UPDATE
INSERT INTO players (display_name, platform, external_user_id, external_username)
VALUES (@Name, 'Telegram', @ExternalId, @Username)
ON CONFLICT (platform, external_user_id)
WHERE platform IS NOT NULL AND external_user_id IS NOT NULL
DO UPDATE
SET display_name = EXCLUDED.display_name,
telegram_username = EXCLUDED.telegram_username,
platform = COALESCE(players.platform, 'Telegram'),
external_user_id = COALESCE(players.external_user_id, EXCLUDED.telegram_id::TEXT),
external_username = COALESCE(players.external_username, EXCLUDED.telegram_username);
external_username = EXCLUDED.external_username;
""",
new { TgId = gmId, Name = gmName, Username = gmUsername },
new { ExternalId = gmId.ToString(), Name = gmName, Username = gmUsername },
transaction);
var existingGroup = await connection.QuerySingleOrDefaultAsync<SessionCreationGroupAccessDto>(
@@ -97,12 +96,14 @@ public sealed class CreateSessionHandler(
FROM group_managers gm
JOIN players p ON p.id = gm.player_id
WHERE gm.group_id = g.id
AND COALESCE(p.external_user_id, p.telegram_id::TEXT) = @GmId::TEXT
AND p.platform = 'Telegram'
AND p.external_user_id = @ExternalGmId
) AS CanManage
FROM game_groups g
WHERE COALESCE(g.external_group_id, g.telegram_chat_id::TEXT) = @ChatId::TEXT
WHERE g.platform = 'Telegram'
AND g.external_group_id = @ExternalChatId
""",
new { ChatId = chatId, GmId = gmId },
new { ExternalChatId = chatId.ToString(), ExternalGmId = gmId.ToString() },
transaction);
Guid groupId;
@@ -110,11 +111,11 @@ public sealed class CreateSessionHandler(
{
groupId = await connection.ExecuteScalarAsync<Guid>(
"""
INSERT INTO game_groups (telegram_chat_id, name, gm_telegram_id, platform, external_group_id)
VALUES (@ChatId, @ChatName, @GmId, 'Telegram', @ChatId::TEXT)
INSERT INTO game_groups (name, platform, external_group_id)
VALUES (@ChatName, 'Telegram', @ExternalChatId)
RETURNING id;
""",
new { ChatId = chatId, ChatName = chatTitle, GmId = gmId },
new { ExternalChatId = chatId.ToString(), ChatName = chatTitle },
transaction);
await connection.ExecuteAsync(
@@ -122,10 +123,11 @@ public sealed class CreateSessionHandler(
INSERT INTO group_managers (group_id, player_id, role)
SELECT @GroupId, p.id, @OwnerRole
FROM players p
WHERE COALESCE(p.external_user_id, p.telegram_id::TEXT) = @GmId::TEXT
WHERE p.platform = 'Telegram'
AND p.external_user_id = @ExternalGmId
ON CONFLICT (group_id, player_id) DO NOTHING
""",
new { GroupId = groupId, GmId = gmId, OwnerRole = GroupManagerRoleExtensions.OwnerValue },
new { GroupId = groupId, ExternalGmId = gmId.ToString(), OwnerRole = GroupManagerRoleExtensions.OwnerValue },
transaction);
}
else