From 67de9e197ad7a623864c148f71005454b14ac786 Mon Sep 17 00:00:00 2001 From: FrigaT Date: Sun, 7 Dec 2025 10:50:58 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BF=D0=B0=D1=80=D1=81=D0=B5=D1=80=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BotPages.Core/Routing/CommandsRegistry.cs | 23 ++++++++++++-------- Demo/Pages/DetailsPage.cs | 26 +++++++++++++---------- Demo/Pages/TitlePage.cs | 3 ++- Demo/Program.cs | 1 + 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/BotPages.Core/Routing/CommandsRegistry.cs b/BotPages.Core/Routing/CommandsRegistry.cs index a63d43e..6006a83 100644 --- a/BotPages.Core/Routing/CommandsRegistry.cs +++ b/BotPages.Core/Routing/CommandsRegistry.cs @@ -49,12 +49,10 @@ internal sealed class CommandsRegistry var match = cmd.Pattern.Match(command); if (match.Success) { - // Собираем аргументы + // Собираем именованные группы (без числовых) var args = cmd.Pattern.GetGroupNames() - .Where(n => n != "0") - .Select(n => new { n, v = match.Groups[n].Value }) - .Where(x => !string.IsNullOrEmpty(x.v)) - .ToDictionary(x => x.n, x => x.v); + .Where(n => !int.TryParse(n, out _)) + .ToDictionary(n => n, n => match.Groups[n].Value); task = cmd.Handler(ctx, args, ct); return true; @@ -64,14 +62,21 @@ internal sealed class CommandsRegistry return false; } + /// + /// Универсальный парсер шаблонов: /cmd {a} {b?} {c} + /// private static Regex ToRegex(string template) { - // Простейшее преобразование шаблона: "/open {page} {id?}" -> Regex var escaped = Regex.Escape(template) .Replace("\\{", "{").Replace("\\}", "}"); - var pattern = "^" + escaped - .Replace("{page}", "(?\\S+)") - .Replace("{id?}", "(?\\S+)?") + "$"; + + var pattern = "^" + Regex.Replace(escaped, @"\{(\w+)(\?)?\}", m => + { + var name = m.Groups[1].Value; + var optional = m.Groups[2].Success; + return optional ? $"(?<{name}>\\S+)?" : $"(?<{name}>\\S+)"; + }) + "$"; + return new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); } diff --git a/Demo/Pages/DetailsPage.cs b/Demo/Pages/DetailsPage.cs index ca7307c..e8559bd 100644 --- a/Demo/Pages/DetailsPage.cs +++ b/Demo/Pages/DetailsPage.cs @@ -1,5 +1,6 @@ using BotPages.Core; using BotPages.Core.Messaging; +using BotPages.Core.Routing; namespace Demo.Pages; @@ -7,20 +8,20 @@ namespace Demo.Pages; /// Страница ввода деталей заявки. /// Страница с параметрами и получением состояния. /// -public sealed class DetailsPage : StatefullPage +public sealed class DetailsPage : StatefullPage { [Statefull("Request")] private Models.Request Request; - public override Task OnEnter(PageContext ctx, DetailsArgs args, CancellationToken ct) + public override Task OnEnter(PageContext ctx, string args, CancellationToken ct) { Request = new() { - Title = args.Title, + Title = args, }; return new MessageBuilder(ctx) - .Text($"Заголовок: {args.Title}\nДобавьте детали или нажмите Далее.") + .Text($"Заголовок: {args}\nДобавьте детали или нажмите Далее.") .Inline(new InlineButton("Далее", "next"), new InlineButton("Назад", "back")) .Reply("Отмена") .SendAsync(ct); @@ -52,12 +53,15 @@ public sealed class DetailsPage : StatefullPage await SaveState(ctx, ct); await ctx.Navigation.GoToAsync(ctx, ct); } -} -/// -/// Аргументы для страницы DetailsPage. -/// -public sealed class DetailsArgs -{ - public string Title { get; set; } = ""; + internal static string Command => "/create_request {title}"; + internal static string CommandDescription => "создание заявки /create_request {title"; + internal static CommandHandler CommandHandler = async (ctx, args, ct) => + { + string? title = ""; + args?.TryGetValue("title", out title); + + // Навигация на страницу по имени + await ctx.Navigation.GoToAsync(ctx, title ?? "", ct); + }; } \ No newline at end of file diff --git a/Demo/Pages/TitlePage.cs b/Demo/Pages/TitlePage.cs index 3e843f1..f270e5d 100644 --- a/Demo/Pages/TitlePage.cs +++ b/Demo/Pages/TitlePage.cs @@ -1,6 +1,7 @@ using BotPages.Core; using BotPages.Core.Abstractions; using BotPages.Core.Messaging; +using BotPages.Core.Routing; namespace Demo.Pages; /// @@ -23,7 +24,7 @@ public sealed class TitlePage : SingletonPage } else { - return ctx.Navigation.GoToAsync(ctx, new DetailsArgs { Title = text }, ct); + return ctx.Navigation.GoToAsync(ctx, text, ct); } } } \ No newline at end of file diff --git a/Demo/Program.cs b/Demo/Program.cs index 5cd2209..355fa7d 100644 --- a/Demo/Program.cs +++ b/Demo/Program.cs @@ -38,6 +38,7 @@ namespace Demo .AddDefaultPage() .MapCommand("/start", true, "Главная") .MapCommand("/open {page}", openHandler, true, "открыть станицу /open {page}") + .MapCommand(DetailsPage.Command, DetailsPage.CommandHandler, true, DetailsPage.CommandDescription) .AutoMapRoute() .AddMiddleware(new ErrorHandlingMiddleware(logger)) .AddMiddleware(new LoggingMiddleware(logger))