fix: close web access to foreign groups and sessions
Deploy Telegram Bot / build-and-push (push) Successful in 7m25s
Deploy Telegram Bot / deploy (push) Successful in 18s

This commit is contained in:
2026-04-23 20:09:22 +03:00
parent ecc2236937
commit 1c4cfb71c0
14 changed files with 352 additions and 49 deletions
+36 -19
View File
@@ -12,7 +12,7 @@ public sealed record WebSession(Guid Id, Guid GroupId, string Title, DateTime Sc
public sealed class SessionService(
NpgsqlDataSource dataSource,
ITelegramBotClient bot,
ILogger<SessionService> logger)
ILogger<SessionService> logger) : ISessionStore
{
public async Task<List<WebGameGroup>> GetGroupsForGmAsync(long gmId)
{
@@ -22,11 +22,19 @@ public sealed class SessionService(
new { GmId = gmId })).ToList();
}
public async Task<WebGameGroup?> GetGroupAsync(Guid groupId)
{
await using var conn = await dataSource.OpenConnectionAsync();
return await conn.QuerySingleOrDefaultAsync<WebGameGroup>(
"SELECT id, telegram_chat_id AS TelegramChatId, name, gm_telegram_id AS GmTelegramId FROM game_groups WHERE id = @GroupId",
new { GroupId = groupId });
}
public async Task<List<WebSession>> GetUpcomingSessionsAsync(Guid groupId)
{
await using var conn = await dataSource.OpenConnectionAsync();
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,
@"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
FROM sessions s
@@ -40,7 +48,7 @@ public sealed class SessionService(
{
await using var conn = await dataSource.OpenConnectionAsync();
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,
@"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
FROM sessions s
@@ -49,29 +57,41 @@ public sealed class SessionService(
new { SessionId = sessionId });
}
public async Task UpdateSessionAsync(Guid sessionId, string title, DateTime scheduledAt, string joinLink)
public async Task UpdateSessionAsync(Guid sessionId, Guid groupId, string title, DateTime scheduledAt, string joinLink)
{
await using var conn = await dataSource.OpenConnectionAsync();
await using var transaction = await conn.BeginTransactionAsync();
// 1. Fetch current session with all required columns for WebSession record
var oldSession = await conn.QuerySingleAsync<WebSession>(
@"SELECT s.id, s.group_id AS GroupId, s.title, s.scheduled_at AS ScheduledAt, s.status, s.join_link AS JoinLink,
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
FROM sessions s
JOIN game_groups g ON g.id = s.group_id
WHERE s.id = @Id",
new { Id = sessionId }, transaction);
// 2. Update Session
await conn.ExecuteAsync(
@"UPDATE sessions SET title = @Title, scheduled_at = @ScheduledAt, join_link = @JoinLink, updated_at = now()
WHERE id = @Id",
new { Id = sessionId, Title = title, ScheduledAt = scheduledAt, JoinLink = joinLink },
WHERE s.id = @Id AND s.group_id = @GroupId",
new { Id = sessionId, GroupId = groupId },
transaction);
// 3. Update all sessions in the same batch with new title (optional, usually batch shares title)
if (oldSession is null)
{
throw new SessionAccessDeniedException(sessionId, 0);
}
var updatedRows = await conn.ExecuteAsync(
@"UPDATE sessions
SET title = @Title,
scheduled_at = @ScheduledAt,
join_link = @JoinLink,
updated_at = now()
WHERE id = @Id AND group_id = @GroupId",
new { Id = sessionId, GroupId = groupId, Title = title, ScheduledAt = scheduledAt, JoinLink = joinLink },
transaction);
if (updatedRows == 0)
{
throw new SessionAccessDeniedException(sessionId, 0);
}
await conn.ExecuteAsync(
"UPDATE sessions SET title = @Title WHERE batch_id = @BatchId",
new { Title = title, BatchId = oldSession.BatchId },
@@ -79,7 +99,6 @@ public sealed class SessionService(
await transaction.CommitAsync();
// 4. Send Telegram Notification
var timeChanged = oldSession.ScheduledAt != scheduledAt;
var notification = $"🔄 <b>Мастер обновил игру!</b>\n\n" +
$"📌 <b>{System.Net.WebUtility.HtmlEncode(title)}</b>\n" +
@@ -87,7 +106,6 @@ public sealed class SessionService(
await bot.SendMessage(oldSession.TelegramChatId, notification, parseMode: Telegram.Bot.Types.Enums.ParseMode.Html);
// 5. Update Original Batch Message
if (oldSession.BatchMessageId.HasValue)
{
await TryUpdateBatchMessageAsync(oldSession.BatchId, oldSession.TelegramChatId, oldSession.BatchMessageId.Value, title);
@@ -124,7 +142,6 @@ public sealed class SessionService(
}
catch (Exception ex)
{
// Log but don't throw — message may be too old or have same content
logger.LogWarning(ex, "Failed to update batch message {MessageId} in chat {ChatId}", messageId, chatId);
}
}