8f0f2ef7e7
Moves the game-creation wizard state machine, view builder, and platform-neutral contracts (callback data, step names, storage exception, club option, step limits) from GmRelay.Bot to GmRelay.Shared. Telegram continues to work through a new TelegramWizardMessenger implementing IWizardMessenger and a WizardInteractionMapper that converts Update → WizardInteraction. Wires the new platform column on wizard_drafts (V032 migration) and switches chat/owner/thread/message ids to TEXT so the same table can hold Discord snowflakes later. - GameCreationWizard: now in Shared, takes IWizardMessenger + IWizardDraftRepository, dispatches on WizardInteraction. - New IWizardMessenger contract with Edit/Send/Answer/GetOwnerClubs (returns string ids so Telegram longs and Discord snowflakes both fit). - New WizardStepViewBuilder in Shared returns (text, IReadOnlyList<WizardAction>); TelegramWizardMessenger renders actions into InlineKeyboardMarkup via a new Bot-side ToInlineKeyboard helper. - New WizardInteractionMapper in Bot (5-case test) converts Telegram Update to WizardInteraction. - WizardDraft gains a Platform column; ChatId/MessageThreadId/OwnerId/ DraftMessageId switched to string. V032 migrates existing rows and rebuilds the owner lookup index on (platform, owner_id). - All existing wizard / create-session tests updated to the new contract (HandleInteractionAsync + WizardInteraction). Wizard callback-data format preserved. - dotnet build clean, dotnet format --verify-no-changes clean, all 101 wizard tests pass.
36 lines
1.3 KiB
C#
36 lines
1.3 KiB
C#
using System;
|
|
|
|
namespace GmRelay.Shared.Features.Sessions.CreateSession.Wizard;
|
|
|
|
/// <summary>
|
|
/// Wire format for wizard callback data. The format is shared by all
|
|
/// platforms (Telegram today, Discord in a follow-up task) and must
|
|
/// stay stable because it is persisted in chat histories and slash-command
|
|
/// autocomplete. Token is <c>wizard</c> to keep the namespace separate
|
|
/// from the rest of the bot's command callbacks.
|
|
/// </summary>
|
|
public static class WizardCallbackData
|
|
{
|
|
public const string Prefix = "wizard";
|
|
|
|
public static string Choice(string step, string choice) => $"{Prefix}:{step}:{choice}";
|
|
|
|
public static string Back() => $"{Prefix}:back";
|
|
|
|
public static string Cancel() => $"{Prefix}:cancel";
|
|
|
|
public static string Create() => $"{Prefix}:create";
|
|
|
|
public static bool TryParse(string? data, out string action, out string step, out string choice)
|
|
{
|
|
action = step = choice = string.Empty;
|
|
if (string.IsNullOrEmpty(data)) return false;
|
|
var parts = data.Split(':', 3);
|
|
if (parts.Length < 2 || parts[0] != Prefix) return false;
|
|
action = parts[1];
|
|
step = parts.Length >= 3 ? parts[1] : string.Empty;
|
|
choice = parts.Length >= 3 ? parts[2] : string.Empty;
|
|
return true;
|
|
}
|
|
}
|