Files
GmRelayBot/RELEASE_NOTES.md
T
Toutsu 014b5edd31
PR Checks / test-and-build (pull_request) Successful in 15m52s
feat(bot): add online/offline wizard locations
Add format and location steps to the Telegram /newsession wizard, persist offline addresses in sessions.location_address, and render online links/offline addresses in schedule messages.

Bump version to 3.10.0.
2026-06-10 11:29:25 +03:00

13 KiB
Raw Blame History

🎯 Minor 3.10.0 — Online/offline format in /newsession wizard (issue #136)

🧩 Что вошло в релиз

  • Telegram /newsession wizard теперь запрашивает формат Online / Offline.
  • Для Online мастер вводит URL подключения; для Offline — адрес места проведения.
  • Offline-адрес сохраняется в sessions.location_address через миграцию V033__add_session_location_address.sql.
  • Telegram schedule messages показывают URL online-игры или адрес offline-встречи; Web duplicate Telegram renderer синхронизирован.

📦 Версия и деплой

  • Версия обновлена до 3.10.0 (Directory.Build.props, NavMenu.razor, .gitea/workflows/deploy.yml).
  • Docker-образы тегируются 3.10.0 в compose.yaml.

🐞 Patch 3.9.2 — Hotfix: club-picker молча падал на шаге «Видимость» (3.9.1 неполный)

В 3.9.1 был починен только WizardDraftRepository (самый частый путь). Тот же баг с (CommandDefinition)-оверлоадом Dapper остался в 4 клуб-пикерах / permission-локапах — Wizard доходил до шага «Видимость», и при выборе «Публичная в витрине клуба» / «Только для членов клуба» PersistAndRenderAsync дёргал _messenger.GetOwnerClubsAsyncPlatformNotSupportedExceptionGameCreationWizard глотал исключение → кнопка ack отправлялась с тостом «⚠️ Ошибка», но нового шага пользователь не видел. Privacy «не цеплялась».

🩹 Что починено

  • src/GmRelay.Bot/Features/Sessions/CreateSession/Wizard/TelegramWizardMessenger.cs::GetOwnerClubsAsyncnew CommandDefinition(...) → прямой QueryAsync<WizardClubOption>(sql, params).
  • src/GmRelay.DiscordBot/Features/Sessions/Wizard/DiscordWizardMessenger.cs::GetOwnerClubsAsync — то же.
  • src/GmRelay.DiscordBot/Features/Sessions/Wizard/DiscordWizardInteractionModule.cs::WizardClubLookup.LoadClubsAsync — то же.
  • src/GmRelay.DiscordBot/Features/Sessions/Wizard/DiscordPermissionLookup.cs::LoadManagerUserIdsAsync — то же.
  • src/GmRelay.DiscordBot/GmRelay.DiscordBot.csproj — добавлен <InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);Dapper.AOT</InterceptorsPreviewNamespaces> (раньше был только в Shared и Bot). Без этого Dapper.AOT-генератор не сканировал DiscordBot, и new CommandDefinition-вызовы в DiscordBot падали бы в рантайме даже после фикса сигнатур.
  • src/GmRelay.DiscordBot/Program.cs — добавлен [module: Dapper.DapperAot] (раньше только в Bot и Shared).
  • Directory.Build.props / compose.yaml / .gitea/workflows/deploy.yml / NavMenu.razor — бамп 3.9.1 → 3.9.2.
  • tests/.../WizardDraftRepositoryAotShapeTests.cs — расширены ClubPickerAndPermissionLookups_ShouldNotUseCommandDefinition на 4 inline-cases + опциональный containingClass для дизамбигуации одинаковых имён методов в DiscordWizardInteractionModule.

⚠️ Известные ограничения

  • Web-проект не под NativeAOT (Blazor Server), там Dapper.AOT не подключён и используется обычный Dapper; регрессия его не касается.

🧪 Тесты

  • 592/594 passed (2 pre-existing skipped), dotnet format clean, dotnet build 0 warnings/errors, AOT-генератор эмитит интерсепторы для всех 4 клуб-пикеров + WizardDraftRepository (всего 5 файлов: 4 в Bot/DiscordBot/DiscordBot + 1 в Shared).

🐞 Patch 3.9.1 — Hotfix: Telegram-визард мёртв после 3.9.0

Регрессия в WizardDraftRepository (NativeAOT). В Telegram не реагировали кнопки и не создавались игры, потому что Dapper.AOT 1.0.48 не генерирует интерсепторы для оверлоада (CommandDefinition) — рантайм падал в CreateParamInfoGeneratorPlatformNotSupportedException на каждом апдейте, TelegramBotService глотал исключение и апдейт терялся.

🩹 Что починено

  • src/GmRelay.Shared/Features/Sessions/CreateSession/Wizard/WizardDraftRepository.cs — все 4 метода переписаны с new CommandDefinition(sql, params, cancellationToken: ct) на прямой оверлоад connection.QuerySingleOrDefaultAsync<WizardDraft>(sql, params) (паттерн JoinSessionHandler). Dapper.AOT генерирует интерсепторы только для прямого оверлоада.
  • src/GmRelay.Shared/Features/Sessions/CreateSession/Wizard/WizardDraft.csCreatedAt / UpdatedAt / ExpiresAt переведены с DateTimeOffset на DateTime (UTC). AOT RowFactory вызывает reader.GetDateTime() напрямую и не делает DateTime → DateTimeOffset конверсию.
  • src/GmRelay.Bot/Features/Sessions/CreateSession/CreateSessionHandler.cs, src/GmRelay.DiscordBot/Features/Sessions/Wizard/DiscordWizardCommand.csDateTimeOffset.UtcNowDateTime.UtcNow в новых драфтах.
  • Directory.Build.props / compose.yaml / .gitea/workflows/deploy.yml / NavMenu.razor — бамп 3.9.0 → 3.9.1.
  • tests/GmRelay.Bot.Tests/Features/Sessions/CreateSession/Wizard/WizardDraftRepositoryAotShapeTests.cs — 5 source-grep регрессионных тестов: ни один метод WizardDraftRepository не должен использовать new CommandDefinition, и три timestamp-свойства WizardDraft должны быть DateTime (не DateTimeOffset).

⚠️ Известные ограничения

  • В TelegramWizardMessenger.GetOwnerClubsAsync, DiscordWizardMessenger.GetOwnerClubsAsync, DiscordPermissionLookup.LoadManagerUserIdsAsync, DiscordWizardInteractionModule.GetOwnerClubsAsync остаётся new CommandDefinition. Эти вызовы падают на AOT так же, как падал WizardDraftRepository в 3.9.0. Пользователь натыкается на это только когда выбирает «видимость = клуб/мемберы» и доходит до шага выбора клуба. Будет исправлено в 3.9.2 вместе с переводом DiscordWizardInteractionModule на прямые Dapper-оверлоады.

🧪 Тесты

  • 588/590 passed (2 pre-existing skipped), dotnet format clean, dotnet build 0 warnings/errors, AOT-генератор эмитит 4 интерсептора + RowFactory17<WizardDraft> + CommandFactory30<WizardDraft>.

🎯 Minor 3.9.0 — Discord-визард создания игры/пула (issue #112)

Пошаговый сценарий создания одиночной игры или пула игр в Discord-чате, по аналогии с Telegram-визардом из 3.8.0. Платформо-нейтральная стейт-машина GameCreationWizard и контракт IWizardMessenger перенесены в GmRelay.Shared, чтобы обе платформы (Telegram/Discord) использовали один и тот же движок визарда.

🧩 Что вошло в релиз

Платформо-нейтральный рефакторинг (GmRelay.Shared)

  • Features/Sessions/CreateSession/Wizard/GameCreationWizard.cs — стейт-машина визарда (один источник правды для обеих платформ)
  • Features/Sessions/CreateSession/Wizard/IWizardMessenger.cs — контракт мессенджера (edit/send/answer/getOwnerClubs)
  • Features/Sessions/CreateSession/Wizard/WizardInteraction.cs — запись взаимодействия (OwnerId, Text, CallbackPayload, PhotoFileId, PhotoUrl, InteractionId)
  • Features/Sessions/CreateSession/Wizard/WizardAction.cs, WizardKeyboard.cs, WizardStepLimits.cs — модель кнопок и лимитов
  • Features/Sessions/CreateSession/Wizard/WizardDraft.cs — добавлено поле Platform
  • Migrations/V032__add_wizard_drafts_platform.sqlALTER TABLE wizard_drafts ADD COLUMN platform TEXT NOT NULL DEFAULT 'Telegram'

Discord-адаптер (GmRelay.DiscordBot)

  • Features/Sessions/Wizard/DiscordWizardCommand.cs — slash-команда /newsession-wizard с проверкой owner/co-GM через DiscordPermissionLookup
  • Features/Sessions/Wizard/DiscordWizardStep.cs — рендер 15 шагов в NetCord embed + buttons/StringSelectMenu/modals
  • Features/Sessions/Wizard/DiscordWizardMessenger.cs — реализация IWizardMessenger через NetCord REST (edit с fallback на re-send при 401/403/404)
  • Features/Sessions/Wizard/DiscordWizardSubmitter.cs — финализация с 3-retry циклом
  • Features/Sessions/Wizard/DiscordWizardContextStore.cs — in-memory кэш контекста (guild/channel/messageId) для 15-минутного interaction token
  • Features/Sessions/Wizard/DiscordWizardInteractionModule.cs — inbound handlers: 3 NetCord ComponentInteractionModule<TContext> (button/StringMenu/Modal) + WizardInteractionDispatcher
  • Features/Sessions/Wizard/DiscordPermissionLookup.cs — DB-хелпер для group_managers
  • Program.cs — DI-регистрации + 3 AddComponentInteractions<TInteraction, TContext>

Тесты

  • tests/GmRelay.Bot.Tests/Features/Sessions/CreateSession/Wizard/* — обновлены под новый контракт
  • tests/GmRelay.Bot.Tests/Discord/DiscordWizardInteractionModuleSourceTests.cs — 12 source-level smoke-тестов на структуру interaction module

🗺 Что это даёт

  • Мастера (GM) могут пошагово создавать игры и пулы слотов прямо в Discord через slash-команду, кнопки, выпадающие меню и модальные окна.
  • UX адаптирован под Discord (нативные components), а не скопирован из Telegram.
  • Общая стейт-машина и валидация: Telegram и Discord визарды развиваются синхронно, баги фиксятся в одном месте.
  • PickClub-шаг использует реальный SQL-запрос к club_memberships с фильтром по роли Owner/CoGm.

📦 Версия и деплой

  • Версия обновлена до 3.9.0 (NavMenu.razor, .gitea/workflows/deploy.yml)
  • Docker-образы будут тегированы 3.9.0 при пуше в main
  • Миграция V032 применяется автоматически на старте Bot

🛠 Patch 2.4.0 — Discord /newsession и /listsessions

Реализованы slash-команды Discord для создания сессий и просмотра расписания без Web Dashboard.

🧩 Что вошло в релиз

  • src/GmRelay.DiscordBot/Features/Sessions/DiscordNewSessionCommand.cs — slash-команда /newsession с параметрами (title, time, seats, link)
  • src/GmRelay.DiscordBot/Features/Sessions/DiscordNewSessionHandler.cs — handler создания batch + session в БД
  • src/GmRelay.DiscordBot/Features/Sessions/DiscordListSessionsCommand.cs — slash-команда /listsessions
  • src/GmRelay.DiscordBot/Features/Sessions/DiscordListSessionsHandler.cs — handler запроса активных сессий с embed-рендерингом
  • src/GmRelay.DiscordBot/Infrastructure/Discord/DiscordPermissionChecker.cs — проверка прав через Discord permissions bitflag (Administrator = 0x8)
  • src/GmRelay.DiscordBot/Infrastructure/Discord/DiscordPlatformMessenger.cs — реализация IPlatformMessenger для Discord через NetCord REST
  • src/GmRelay.DiscordBot/Program.cs — регистрация DI: handlers, permission checker, messenger
  • ests/GmRelay.Bot.Tests/Discord/ — 20+ TDD-тестов на парсинг, права, структуру, DI, рендеринг
  • Синхронизированы версии: Directory.Build.props, NavMenu.razor, compose.yaml, deploy.yml → 2.4.0

🗺 Что это даёт

  • Мастера (GM) могут создавать сессии прямо из Discord, не заходя в Web.
  • Участники сервера видят расписание через /listsessions.
  • Единая PostgreSQL модель для Telegram и Discord — никакого дублирования данных.

📦 Версия и деплой

  • версия обновлена до 2.4.0
  • Docker-образы используют тег 2.4.0