Commit Graph

16 Commits

Author SHA1 Message Date
Toutsu 2c9016a383 fix(shared,bot,discordbot): make club-picker Dapper calls AOT-safe (v3.9.2)
Deploy Telegram Bot / build-and-push (push) Successful in 7m18s
Deploy Telegram Bot / scan-images (push) Failing after 17s
Deploy Telegram Bot / deploy (push) Has been skipped
The 3.9.1 hotfix only repaired WizardDraftRepository, the most common
Dapper call in the wizard. The same AOT-unsafe CommandDefinition pattern
remained in 4 other places that the user hit immediately after the
deploy: the 'Choose visibility' wizard step triggers GetOwnerClubsAsync
when the user picks 'Публичная в витрине клуба' or 'Только для членов
клуба'. The wizard swallowed PlatformNotSupportedException, the
callback ack replied with '⚠️ Ошибка', and the next step never rendered.
Privacy 'didn't stick' from the user's perspective.

Two changes to fix the Discord side as well:

1. Switched GetOwnerClubsAsync / LoadClubsAsync / LoadManagerUserIdsAsync
   to the direct (sql, params) overload across TelegramWizardMessenger,
   DiscordWizardMessenger, DiscordWizardInteractionModule, and
   DiscordPermissionLookup — same pattern as the 3.9.1 fix.

2. Added Dapper.AOT module attribute ([module: Dapper.DapperAot]) and
   InterceptorsPreviewNamespaces to the DiscordBot project. The
   DiscordBot assembly was previously skipped by the AOT source
   generator, so even the direct-overload fix wouldn't have produced
   interceptors for the Discord-specific Dapper call sites. With this
   addition, the generator emits 3 DiscordBot-specific interceptors
   (DiscordWizardMessenger, DiscordWizardInteractionModule,
   DiscordPermissionLookup) and the AssemblyLoad ships with the right
   GmRelay.DiscordBot.generated.cs.

Also expanded the AOT shape regression tests to cover all 4
CommandDefinition sites + added a 'containingClass' parameter to
ExtractMethodBody to disambiguate the duplicated LoadClubsAsync names
in DiscordWizardInteractionModule.

Bumps: 3.9.1 -> 3.9.2.
2026-06-08 10:48:24 +03:00
Coder f0952096f3 feat(discord): wizard interaction handlers + DI for StringMenu/Modal (issue #112)
Adds the missing inbound handlers for the Discord wizard that the
previous commit (b81d865) left out. Three thin NetCord module classes
share one WizardInteractionDispatcher:

- DiscordWizardButtonModule
- DiscordWizardStringMenuModule
- DiscordWizardModalModule

Each registers a single [ComponentInteraction("wizard")] method that
hands the args string to the dispatcher. The dispatcher parses the
custom-id tail (btn:choice:<step>:<value>, btn:back, btn:cancel,
btn:create, btn:resume:continue, btn:resume:restart, select:<step>,
modal:<step>), looks up the active draft by (platform="Discord",
ownerId=userId), and routes through the shared
GameCreationWizard.HandleInteractionAsync. The "create" callback
delegates to DiscordWizardSubmitter.SubmitAsync (3-retry finalize).

Program.cs gets 4 new singleton registrations (the dispatcher plus
the three module classes) and 2 new AddComponentInteractions calls
(StringMenu + Modal). The existing Button registration is unchanged.

12 new source-level smoke tests in DiscordWizardInteractionModuleSourceTests
cover the file shape: 3 handler classes, 3 base classes, 3
[ComponentInteraction] registrations, all 5 callback kinds parsed,
GameCreationWizard wired in, submitter invoked on create, Program.cs
registers all 3 AddComponentInteractions and all 4 module classes,
draft lookup by GetActiveAsync("Discord", ...), modal walks
Components[0] -> TextInput -> .Value, string menu reads
SelectedValues[0].

Build green. 190/190 Discord+Wizard tests pass (2 pre-existing
skipped). dotnet format clean.
2026-06-05 18:31:47 +03:00
Coder b81d865832 feat(discord): step-by-step game/pool creation wizard (issue #112)
Add Discord adapter for the platform-neutral wizard moved to Shared in
the previous commit. Six new files in src/GmRelay.DiscordBot/Features/
Sessions/Wizard/:

- DiscordWizardContextStore: IWizardContextStore abstraction +
  thread-safe in-memory impl keyed by draft id. Holds the (guild,
  channel, message) coordinates the messenger needs to re-send the
  draft after a 15-minute interaction token expires.
- DiscordWizardStep: renderer for all 15 wizard steps. Returns an
  embed plus an IReadOnlyList<IMessageComponentProperties> that mixes
  ActionRow buttons with StringMenu select menus. Also exposes
  BuildModal for the 8 modal-collecting steps.
- DiscordWizardMessenger: IWizardMessenger impl backed by NetCord's
  RestClient + NpgsqlDataSource. Edit falls back to re-send on
  401/403/404. Toast replies are stashed in the existing
  DiscordInteractionReplyCache.
- DiscordWizardSubmitter: 3-retry finalize loop. Builds the shared
  CreateSessionCommand and calls CreateSessionHandler; on success
  edits the message to "ok Created: N sessions", on failure shows
  retry/cancel buttons.
- DiscordWizardCommand: /newsession-wizard slash command with an
  optional mode param (single|pool). Owner/co-GM check via the
  shared group_managers table.
- DiscordPermissionLookup: small helper that loads DB manager ids
  for a guild.

Program.cs gets 5 new singleton registrations (IWizardDraftRepository,
IWizardContextStore, IWizardMessenger, GameCreationWizard,
DiscordWizardSubmitter). The slash command is auto-discovered by
AddApplicationCommands<SlashCommandInteraction, SlashCommandContext>()
+ AddModules(typeof(Program).Assembly).

Build green. All 85 wizard tests + 95 Discord tests pass.
dotnet format clean.

Open: DiscordWizardInteractionModule (button/modal handlers) is not
yet implemented; the bot starts and /newsession-wizard works to the
point of posting the first embed, but subsequent button clicks won't
be handled. A follow-up commit will add the component-interaction
module.
2026-06-05 17:52:29 +03:00
Toutsu 542f15f2d6 refactor: extract remaining Telegram handlers to platform-neutral contracts
PR Checks / test-and-build (pull_request) Successful in 13m48s
- Extract CreateSessionHandler, ListSessionsHandler, DeleteSessionHandler,
  ExportCalendarHandler, HandleRescheduleTimeInputHandler,
  HandleRescheduleVoteHandler to GmRelay.Shared
- Add IPlatformMessenger methods: SendScheduleAsync, UpdateScheduleAsync,
  SendGroupMessageAsync with actions, CreateThreadAsync, DeleteThreadAsync
- Rewrite Telegram Bot wrappers as thin adapters delegating to shared handlers
- Rewrite DiscordRescheduleVoteHandler to use shared HandleRescheduleVoteHandler
- Update UpdateRouter with explicit type aliases for ambiguous handler names
- Add contract and source-inspection tests for extracted handlers
- Bump version 3.1.1 → 3.2.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 14:52:09 +03:00
Toutsu 3447acd8c4 fix(discord): update sessions via interactions
Deploy Telegram Bot / build-and-push (push) Successful in 6m14s
Deploy Telegram Bot / scan-images (push) Successful in 3m12s
Deploy Telegram Bot / deploy (push) Successful in 31s
2026-05-26 14:24:06 +03:00
Toutsu a5624897e9 fix(discord): add console logging and deferred responses
PR Checks / test-and-build (pull_request) Failing after 12m3s
- Add builder.Logging.AddConsole() to DiscordBot Program.cs so logs
  are visible in docker logs.
- Add granular LogInformation/LogError calls to DiscordNewSessionCommand
  and DiscordRescheduleCommand to diagnose failures.
- Use InteractionCallback.DeferredMessage() + ModifyResponseAsync pattern
  for /newsession and /reschedule to avoid Discord 3-second interaction
  timeout.
- Bump version → 3.0.8

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 11:18:09 +03:00
Toutsu d931da37ec fix(discord): use correct slash command context type in AddApplicationCommands
PR Checks / test-and-build (pull_request) Failing after 8m7s
The default AddApplicationCommands() registers ApplicationCommandService<ApplicationCommandContext>,
but our modules inherit ApplicationCommandModule<SlashCommandContext>. Because SlashCommandContext
does not inherit from ApplicationCommandContext in NetCord, AddModules(typeof(Program).Assembly)
failed to discover the modules, so /newsession, /listsessions, /reschedule were never published
to Discord. Only /ping worked because it uses the minimal API route.

Fix: specify AddApplicationCommands<SlashCommandInteraction, SlashCommandContext>() so the
service matches the module context type, allowing module discovery to succeed.

Bump version to 3.0.4.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 17:05:51 +03:00
Toutsu eff0128d29 fix(discord): register slash command modules
PR Checks / test-and-build (pull_request) Successful in 8m27s
Register NetCord application command modules after the host is built so module-based commands are published alongside the minimal /ping command.

Update README Discord env guidance to avoid the unused DISCORD_BOT_CLIENT_ID variable.

Bump version to 3.0.2.
2026-05-25 15:49:36 +03:00
Toutsu feb3e08b63 feat(discord): register health check hosted service in Program.cs
Issue #32
2026-05-21 14:20:40 +03:00
Toutsu 2a707e4825 feat(platform): route scheduler notifications through platform messenger
PR Checks / test-and-build (pull_request) Successful in 7m9s
2026-05-21 12:30:35 +03:00
Toutsu 690aa0272f feat(discord): add reschedule voting deadline service 2026-05-20 12:29:33 +03:00
Toutsu fdfc73ae9c feat(discord): add reschedule vote button handler 2026-05-20 12:21:13 +03:00
Toutsu e93e777fb3 feat(discord): add /reschedule slash command and handler 2026-05-20 12:15:03 +03:00
Toutsu 39132be4e8 feat(discord): enable session join leave buttons
PR Checks / test-and-build (pull_request) Successful in 6m6s
Move neutral join/leave handlers into GmRelay.Shared so Telegram and Discord share capacity, waitlist, duplicate-click, and schedule-update behavior.

Add Discord component routing for join_session and leave_session buttons with deferred ephemeral replies and serialized schedule message updates.

Bump version to 2.5.0 and update Discord docs.

Refs #29
2026-05-19 14:13:48 +03:00
Toutsu 8666b8984e feat: register Discord session handlers and permission checker in DI
Task 5: DI wiring for DiscordNewSessionHandler, DiscordListSessionsHandler,
DiscordPermissionChecker, and DiscordPlatformMessenger.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 11:33:33 +03:00
Toutsu 05ca8061e9 feat: add Discord NetCord gateway worker
PR Checks / test-and-build (pull_request) Successful in 5m46s
Add a separate GmRelay.DiscordBot worker using NetCord Gateway with startup token validation, PostgreSQL datasource registration, slash-command setup, component interaction service registration, and lifecycle logging.

Wire the Discord service through Aspire AppHost, Docker Compose, PR checks, deploy image build/push/scan/pull steps, README docs, and synchronized version 2.2.0.

Add TDD coverage for project isolation, token validation, startup wiring, runtime wiring, and version synchronization.

Bump version -> 2.2.0
2026-05-18 16:04:31 +03:00