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
+27 -27
View File
@@ -121,7 +121,7 @@ public sealed class SessionService(
GROUP BY gm.group_id
)
SELECT g.id,
g.telegram_chat_id AS TelegramChatId,
g.external_group_id::BIGINT AS TelegramChatId,
g.external_group_id AS ExternalGroupId,
COALESCE(NULLIF(g.name, g.external_group_id), latest_session.title, g.name) AS Name,
g.platform AS Platform,
@@ -151,7 +151,7 @@ public sealed class SessionService(
return await conn.QuerySingleOrDefaultAsync<WebGameGroup>(
"""
SELECT g.id,
g.telegram_chat_id AS TelegramChatId,
g.external_group_id::BIGINT AS TelegramChatId,
g.external_group_id AS ExternalGroupId,
COALESCE(NULLIF(g.name, g.external_group_id), latest_session.title, g.name) AS Name,
g.platform AS Platform,
@@ -213,11 +213,11 @@ public sealed class SessionService(
await using var conn = await dataSource.OpenConnectionAsync();
return (await conn.QueryAsync<WebGroupManager>(
"""
SELECT COALESCE(p.telegram_id, 0) AS TelegramId,
COALESCE(p.external_user_id, p.telegram_id::TEXT) AS ExternalUserId,
SELECT COALESCE(p.external_user_id::BIGINT, 0) AS TelegramId,
p.external_user_id AS ExternalUserId,
p.display_name AS DisplayName,
p.telegram_username AS TelegramUsername,
COALESCE(p.external_username, p.telegram_username) AS ExternalUsername,
p.external_username AS TelegramUsername,
p.external_username AS ExternalUsername,
gm.role AS Role,
gm.created_at AS AddedAt
FROM group_managers gm
@@ -238,7 +238,7 @@ public sealed class SessionService(
SELECT
p.id AS PlayerId,
p.display_name AS DisplayName,
COALESCE(p.external_username, p.telegram_username) AS ExternalUsername,
p.external_username AS ExternalUsername,
COUNT(DISTINCT s.id) AS TotalSessions,
COUNT(DISTINCT CASE WHEN sp.rsvp_status = 'Confirmed' THEN s.id END) AS ConfirmedCount,
COUNT(DISTINCT CASE WHEN sp.rsvp_status = 'Declined' THEN s.id END) AS DeclinedCount,
@@ -257,7 +257,7 @@ public sealed class SessionService(
WHERE s.group_id = @GroupId
AND s.scheduled_at <= now()
AND sp.is_gm = false
GROUP BY p.id, p.display_name, p.external_username, p.telegram_username
GROUP BY p.id, p.display_name, p.external_username
ORDER BY AttendanceRate DESC, ConfirmedCount DESC
""",
new { GroupId = groupId })).ToList();
@@ -356,7 +356,7 @@ public sealed class SessionService(
return (await conn.QueryAsync<WebSession>(
@"SELECT s.id, s.group_id AS GroupId, s.title, s.scheduled_at AS ScheduledAt, s.status, s.join_link AS JoinLink,
s.batch_id AS BatchId, s.batch_message_id AS BatchMessageId,
g.telegram_chat_id AS TelegramChatId,
g.external_group_id::BIGINT AS TelegramChatId,
s.max_players AS MaxPlayers,
COALESCE(active_counts.count, 0)::int AS ActivePlayerCount,
COALESCE(waitlist_counts.count, 0)::int AS WaitlistedPlayerCount,
@@ -394,7 +394,7 @@ public sealed class SessionService(
return await conn.QuerySingleOrDefaultAsync<WebSession>(
@"SELECT s.id, s.group_id AS GroupId, s.title, s.scheduled_at AS ScheduledAt, s.status, s.join_link AS JoinLink,
s.batch_id AS BatchId, s.batch_message_id AS BatchMessageId,
g.telegram_chat_id AS TelegramChatId,
g.external_group_id::BIGINT AS TelegramChatId,
s.max_players AS MaxPlayers,
COALESCE(active_counts.count, 0)::int AS ActivePlayerCount,
COALESCE(waitlist_counts.count, 0)::int AS WaitlistedPlayerCount,
@@ -453,7 +453,7 @@ public sealed class SessionService(
var oldSession = await conn.QuerySingleOrDefaultAsync<WebSession>(
@"SELECT s.id, s.group_id AS GroupId, s.title, s.scheduled_at AS ScheduledAt, s.status, s.join_link AS JoinLink,
s.batch_id AS BatchId, s.batch_message_id AS BatchMessageId,
g.telegram_chat_id AS TelegramChatId,
g.external_group_id::BIGINT AS TelegramChatId,
s.max_players AS MaxPlayers,
0 AS ActivePlayerCount,
0 AS WaitlistedPlayerCount,
@@ -539,7 +539,7 @@ public sealed class SessionService(
var session = await conn.QuerySingleOrDefaultAsync<WebSession>(
@"SELECT s.id, s.group_id AS GroupId, s.title, s.scheduled_at AS ScheduledAt, s.status, s.join_link AS JoinLink,
s.batch_id AS BatchId, s.batch_message_id AS BatchMessageId,
g.telegram_chat_id AS TelegramChatId,
g.external_group_id::BIGINT AS TelegramChatId,
s.max_players AS MaxPlayers,
0 AS ActivePlayerCount,
0 AS WaitlistedPlayerCount,
@@ -638,11 +638,11 @@ public sealed class SessionService(
return (await conn.QueryAsync<WebParticipant>(
"""
SELECT sp.id AS Id,
COALESCE(p.telegram_id, 0) AS TelegramId,
COALESCE(p.external_user_id, p.telegram_id::TEXT) AS ExternalUserId,
COALESCE(p.external_user_id::BIGINT, 0) AS TelegramId,
p.external_user_id AS ExternalUserId,
p.display_name AS DisplayName,
p.telegram_username AS TelegramUsername,
COALESCE(p.external_username, p.telegram_username) AS ExternalUsername,
p.external_username AS TelegramUsername,
p.external_username AS ExternalUsername,
sp.rsvp_status AS RsvpStatus,
sp.registration_status AS RegistrationStatus,
sp.is_gm AS IsGm,
@@ -665,7 +665,7 @@ public sealed class SessionService(
var session = await conn.QuerySingleOrDefaultAsync<WebSession>(
@"SELECT s.id, s.group_id AS GroupId, s.title, s.scheduled_at AS ScheduledAt, s.status, s.join_link AS JoinLink,
s.batch_id AS BatchId, s.batch_message_id AS BatchMessageId,
g.telegram_chat_id AS TelegramChatId,
g.external_group_id::BIGINT AS TelegramChatId,
s.max_players AS MaxPlayers,
0 AS ActivePlayerCount,
0 AS WaitlistedPlayerCount,
@@ -686,9 +686,9 @@ public sealed class SessionService(
var participant = await conn.QuerySingleOrDefaultAsync<WebParticipant>(
"""
SELECT sp.id AS Id,
p.telegram_id AS TelegramId,
p.external_user_id::BIGINT AS TelegramId,
p.display_name AS DisplayName,
p.telegram_username AS TelegramUsername,
p.external_username AS TelegramUsername,
sp.rsvp_status AS RsvpStatus,
sp.registration_status AS RegistrationStatus,
sp.is_gm AS IsGm,
@@ -871,7 +871,7 @@ public sealed class SessionService(
s.status AS Status,
s.max_players AS MaxPlayers,
s.batch_message_id AS BatchMessageId,
g.telegram_chat_id AS TelegramChatId,
g.external_group_id::BIGINT AS TelegramChatId,
s.thread_id AS ThreadId,
s.topic_created_by_bot AS TopicCreatedByBot,
s.notification_mode AS NotificationMode
@@ -955,7 +955,7 @@ public sealed class SessionService(
s.status AS Status,
s.max_players AS MaxPlayers,
s.batch_message_id AS BatchMessageId,
g.telegram_chat_id AS TelegramChatId,
g.external_group_id::BIGINT AS TelegramChatId,
s.thread_id AS ThreadId,
s.topic_created_by_bot AS TopicCreatedByBot,
s.notification_mode AS NotificationMode
@@ -1177,7 +1177,7 @@ public sealed class SessionService(
}
var group = await conn.QuerySingleOrDefaultAsync<WebTemplateGroupDto>(
"SELECT telegram_chat_id AS TelegramChatId FROM game_groups WHERE id = @GroupId",
"SELECT external_group_id::BIGINT AS TelegramChatId FROM game_groups WHERE id = @GroupId",
new { GroupId = groupId },
transaction);
@@ -1248,7 +1248,7 @@ public sealed class SessionService(
{
return (await conn.QueryAsync<WebDirectNotificationRecipient>(
"""
SELECT p.telegram_id AS TelegramId,
SELECT p.external_user_id::BIGINT AS TelegramId,
p.display_name AS DisplayName
FROM session_participants sp
JOIN players p ON p.id = sp.player_id
@@ -1265,7 +1265,7 @@ public sealed class SessionService(
{
return (await conn.QueryAsync<WebDirectNotificationRecipient>(
"""
SELECT DISTINCT p.telegram_id AS TelegramId,
SELECT DISTINCT p.external_user_id::BIGINT AS TelegramId,
p.display_name AS DisplayName
FROM session_participants sp
JOIN players p ON p.id = sp.player_id
@@ -1318,7 +1318,7 @@ public sealed class SessionService(
var participants = (await conn.QueryAsync<ParticipantBatchDto>(
@"SELECT sp.session_id AS SessionId,
p.display_name AS DisplayName,
p.telegram_username AS TelegramUsername,
p.external_username AS TelegramUsername,
sp.registration_status AS RegistrationStatus
FROM session_participants sp
JOIN players p ON sp.player_id = p.id
@@ -1355,7 +1355,7 @@ public sealed class SessionService(
s.group_id AS GroupId,
(array_agg(s.title ORDER BY s.scheduled_at))[1] AS Title,
(array_agg(s.join_link ORDER BY s.scheduled_at))[1] AS JoinLink,
g.telegram_chat_id AS TelegramChatId,
g.external_group_id::BIGINT AS TelegramChatId,
(array_agg(s.batch_message_id ORDER BY s.scheduled_at))[1] AS BatchMessageId,
(array_agg(s.thread_id ORDER BY s.scheduled_at))[1] AS ThreadId,
(array_agg(s.notification_mode ORDER BY s.scheduled_at))[1] AS NotificationMode
@@ -1363,7 +1363,7 @@ public sealed class SessionService(
JOIN game_groups g ON g.id = s.group_id
WHERE s.batch_id = @BatchId
AND s.group_id = @GroupId
GROUP BY s.batch_id, s.group_id, g.telegram_chat_id
GROUP BY s.batch_id, s.group_id, g.external_group_id
""",
new { BatchId = batchId, GroupId = groupId },
transaction);