refactor: add platform messenger contracts
PR Checks / test-and-build (pull_request) Successful in 12m35s

Introduce platform-neutral PlatformKind, PlatformUser, PlatformGroup, and IPlatformMessenger contracts in GmRelay.Shared.

Route Telegram session schedule updates, direct notifications, interaction replies, and calendar export through TelegramPlatformMessenger while preserving existing Telegram behavior.

Bump version -> 2.0.1
This commit is contained in:
2026-05-15 12:30:37 +03:00
parent 7cecb722d8
commit 8bcd16fbc9
27 changed files with 1133 additions and 180 deletions
@@ -1,10 +1,9 @@
using Dapper;
using GmRelay.Bot.Features.Notifications;
using GmRelay.Shared.Domain;
using GmRelay.Shared.Platform;
using GmRelay.Shared.Rendering;
using Npgsql;
using Telegram.Bot;
using Telegram.Bot.Types;
using GmRelay.Bot.Infrastructure.Telegram;
namespace GmRelay.Bot.Features.Sessions.CreateSession;
@@ -22,7 +21,7 @@ internal sealed record CancelSessionInfoDto(string Title, Guid BatchId, int? Bat
public sealed class CancelSessionHandler(
NpgsqlDataSource dataSource,
ITelegramBotClient bot,
IPlatformMessenger messenger,
DirectSessionNotificationSender directSender,
ILogger<CancelSessionHandler> logger)
{
@@ -52,13 +51,13 @@ public sealed class CancelSessionHandler(
if (session == null)
{
await bot.AnswerCallbackQuery(command.CallbackQueryId, "Сессия не найдена.", cancellationToken: ct);
await AnswerAsync(command.CallbackQueryId, "Сессия не найдена.", ct);
return;
}
if (!session.CanManage)
{
await bot.AnswerCallbackQuery(command.CallbackQueryId, "Только owner или co-GM может отменять сессию.", showAlert: true, cancellationToken: ct);
await AnswerAsync(command.CallbackQueryId, "Только owner или co-GM может отменять сессию.", ct, showAlert: true);
return;
}
@@ -105,27 +104,24 @@ public sealed class CancelSessionHandler(
// 4. Перерисовываем сообщение
var view = SessionBatchViewBuilder.Build(session.Title, batchSessions.ToList(), batchParticipants.ToList());
var renderResult = TelegramSessionBatchRenderer.Render(view);
try
{
await BatchMessageEditor.EditBatchMessageAsync(
bot,
chatId: command.ChatId,
messageId: session.BatchMessageId ?? command.MessageId,
text: renderResult.Text,
replyMarkup: renderResult.Markup,
var messageId = session.BatchMessageId ?? command.MessageId;
await messenger.UpdateScheduleAsync(
new PlatformScheduleMessage(
TelegramPlatformIds.Group(command.ChatId, command.MessageThreadId),
view,
TelegramPlatformIds.Message(command.ChatId, command.MessageThreadId, messageId)),
ct);
await bot.AnswerCallbackQuery(command.CallbackQueryId, "Сессия отменена!", cancellationToken: ct);
await AnswerAsync(command.CallbackQueryId, "Сессия отменена!", ct);
// Опционально: написать отдельное сообщение в чат
await bot.SendMessage(
chatId: command.ChatId,
messageThreadId: command.MessageThreadId,
text: $"❌ <b>Внимание!</b> Сессия \"{System.Net.WebUtility.HtmlEncode(session.Title)}\" отменена.",
parseMode: Telegram.Bot.Types.Enums.ParseMode.Html,
cancellationToken: ct);
await messenger.SendGroupMessageAsync(
TelegramPlatformIds.Group(command.ChatId, command.MessageThreadId),
$"❌ <b>Внимание!</b> Сессия \"{System.Net.WebUtility.HtmlEncode(session.Title)}\" отменена.",
ct);
var mode = SessionNotificationModeExtensions.FromDatabaseValue(session.NotificationMode);
if (mode.ShouldSendDirectMessages())
@@ -141,7 +137,10 @@ public sealed class CancelSessionHandler(
catch (Exception ex)
{
logger.LogError(ex, "Failed to update batch message after cancelling session {SessionId}", command.SessionId);
await bot.AnswerCallbackQuery(command.CallbackQueryId, "Ошибка при обновлении сообщения.", cancellationToken: ct);
await AnswerAsync(command.CallbackQueryId, "Ошибка при обновлении сообщения.", ct);
}
}
private Task AnswerAsync(string callbackQueryId, string text, CancellationToken ct, bool showAlert = false) =>
messenger.AnswerInteractionAsync(new PlatformInteractionReply(callbackQueryId, text, showAlert), ct);
}