feat(discord): step-by-step game/pool creation wizard (issue #112) #122

Merged
Toutsu merged 8 commits from feat/issue-112-wizard-refactor into main 2026-06-06 08:04:16 +03:00
Showing only changes of commit c4a77d3d73 - Show all commits
+24 -17
View File
@@ -107,23 +107,21 @@ PR link: https://git.codeanddice.ru/Toutsu/GmRelayBot/pulls/new/feat/issue-112-w
## Open questions
- **Club lookup at the PickClub step** — `DiscordWizardMessenger.GetOwnerClubsAsync`
queries `group_managers` for the user's owned/co-GM groups; the
dispatcher's `WizardClubLookup` stub currently returns an empty list
(DB access goes through `DiscordWizardMessenger`, which is a sibling
of the dispatcher in DI). The actual `DiscordWizardMessenger.SendDraftMessageAsync`
path also has the same gap: it doesn't pre-populate clubs. At runtime
the user sees "У вас нет клубов" at the PickClub step even if they
actually own clubs. The fix is to plumb `NpgsqlDataSource` (or the
messenger itself) into the dispatcher.
- **MaybeOpenModalAsync was a no-op in the previous commit.** The
fix: don't defer the interaction response before the wizard runs;
instead, run the wizard (which edits the draft embed), then send
the response as either `InteractionCallback.Modal(modalProperties)`
(when the new step needs text input) or
`InteractionCallback.DeferredMessage()` (otherwise). NetCord locks
the response type after the first `SendResponseAsync` call, so the
fix requires NOT calling `DeferredMessage` upfront.
- ~~**Club lookup at the PickClub step**~~**FIXED in commit `7cfb196`.**
`WizardClubLookup.LoadClubsAsync` now queries `group_managers`
directly via injected `NpgsqlDataSource` with the same
`Owner | CoGm` role filter the messenger uses. The dispatcher
reads the owner's real club list and renders them in the
StringSelectMenu. Build green, 12 source-level smoke tests still
pass.
- ~~**MaybeOpenModalAsync was a no-op in the previous commit**~~ — **FIXED in commit `f095209`.**
The dispatcher now runs the wizard first (which edits the draft
embed), then sends the response as either
`InteractionCallback.Modal(modalProperties)` (when the new step
needs text input) or `InteractionCallback.DeferredMessage()`
(otherwise). NetCord locks the response type after the first
`SendResponseAsync` call, so the fix is NOT to call
`DeferredMessage` upfront.
- **Modal handler's free-text mapping is a hack.** Modal steps like
`SystemFreeText`, `DurationFreeText`, `PoolSystemDurationFreeText`
are mapped to the canonical wizard step (`System`, `Duration`,
@@ -144,3 +142,12 @@ PR link: https://git.codeanddice.ru/Toutsu/GmRelayBot/pulls/new/feat/issue-112-w
sessions in parallel. Acceptable for now, but the wizard's state
machine doesn't enforce this — only the dispatcher does, via
`GetActiveAsync("Discord", ownerId)`.
## Final commit history on `feat/issue-112-wizard-refactor`
- `8f0f2ef` — Task 1: platform-neutral wizard refactor (core + Shared types)
- `b81d865` — Task 2: Discord adapter scaffolding (messenger, step, submitter, command)
- `f095209` — Task 2: interaction module + modal popup fix
- `7cfb196` — Task 2: select/modal parser off-by-one + real club lookup
PR link: https://git.codeanddice.ru/Toutsu/GmRelayBot/pulls/new/feat/issue-112-wizard-refactor