From e1a98790b095bd60ffb75bef6dbe93818fe2fc2a Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Fri, 26 Jul 2024 22:30:18 +0200 Subject: [PATCH 01/66] feat: update sdk to version 8 --- src/global.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/global.json b/src/global.json index c8f68bd..cfa048e 100644 --- a/src/global.json +++ b/src/global.json @@ -1,6 +1,6 @@ { "sdk": { - "rollForward": "feature", - "version": "7.0.111" + "version": "8.0.0", + "rollForward": "feature" } } \ No newline at end of file From 80865ae90d3e1c9071ccd852e3d7425bbc205046 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Fri, 26 Jul 2024 22:30:52 +0200 Subject: [PATCH 02/66] feat: add nuget.config Should be temporal in order to use Teleram.Bot until they solve their problem with nuget. --- src/nuget.config | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/nuget.config diff --git a/src/nuget.config b/src/nuget.config new file mode 100644 index 0000000..4d77fc1 --- /dev/null +++ b/src/nuget.config @@ -0,0 +1,6 @@ + + + + + + From b9a893d825d46f9ef90276b3f88a176467febf15 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Fri, 26 Jul 2024 22:31:55 +0200 Subject: [PATCH 03/66] feat: update projects and packages --- .../Navigator.Extensions.Store.csproj | 2 +- .../NavigatorContextExtensions.cs | 3 ++- src/Navigator.sln | 2 ++ src/Navigator/Navigator.csproj | 10 +++++----- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Navigator.Extensions.Store/Navigator.Extensions.Store.csproj b/src/Navigator.Extensions.Store/Navigator.Extensions.Store.csproj index 53add6e..e7a43fb 100644 --- a/src/Navigator.Extensions.Store/Navigator.Extensions.Store.csproj +++ b/src/Navigator.Extensions.Store/Navigator.Extensions.Store.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 true enable true diff --git a/src/Navigator.Extensions.Store/NavigatorContextExtensions.cs b/src/Navigator.Extensions.Store/NavigatorContextExtensions.cs index dad3d45..132f82f 100644 --- a/src/Navigator.Extensions.Store/NavigatorContextExtensions.cs +++ b/src/Navigator.Extensions.Store/NavigatorContextExtensions.cs @@ -1,5 +1,6 @@ -using Navigator.Context; using Navigator.Extensions.Store.Context; +using Navigator.Old; +using Navigator.Old.Context; namespace Navigator.Extensions.Store; diff --git a/src/Navigator.sln b/src/Navigator.sln index f191e02..e52b066 100644 --- a/src/Navigator.sln +++ b/src/Navigator.sln @@ -16,6 +16,8 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".solution-items", ".solution-items", "{731D9036-DAE1-4300-825D-37C6F25C4F60}" ProjectSection(SolutionItems) = preProject ..\.github\workflows\package.navigator.yml = ..\.github\workflows\package.navigator.yml + global.json = global.json + nuget.config = nuget.config EndProjectSection EndProject Global diff --git a/src/Navigator/Navigator.csproj b/src/Navigator/Navigator.csproj index daa8676..76f6e33 100644 --- a/src/Navigator/Navigator.csproj +++ b/src/Navigator/Navigator.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 true enable true @@ -28,11 +28,11 @@ - - - + + + - + From f2b6db63ceb4ef56df98d898d0199b07befa13c8 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Fri, 26 Jul 2024 22:43:51 +0200 Subject: [PATCH 04/66] feat: solve initial problems after update --- .../NavigatorContextExtensions.cs | 3 +-- .../Actions/Messages/UserSharedAction.cs | 23 ------------------- .../EndpointRouteBuilderExtensions.cs | 3 +-- src/Navigator/TelegramMiddleware.cs | 1 - 4 files changed, 2 insertions(+), 28 deletions(-) delete mode 100644 src/Navigator/Bundled/Actions/Messages/UserSharedAction.cs diff --git a/src/Navigator.Extensions.Store/NavigatorContextExtensions.cs b/src/Navigator.Extensions.Store/NavigatorContextExtensions.cs index 132f82f..dad3d45 100644 --- a/src/Navigator.Extensions.Store/NavigatorContextExtensions.cs +++ b/src/Navigator.Extensions.Store/NavigatorContextExtensions.cs @@ -1,6 +1,5 @@ +using Navigator.Context; using Navigator.Extensions.Store.Context; -using Navigator.Old; -using Navigator.Old.Context; namespace Navigator.Extensions.Store; diff --git a/src/Navigator/Bundled/Actions/Messages/UserSharedAction.cs b/src/Navigator/Bundled/Actions/Messages/UserSharedAction.cs deleted file mode 100644 index 4c0f0c9..0000000 --- a/src/Navigator/Bundled/Actions/Messages/UserSharedAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered when a user shared content. -/// -[ActionType(nameof(UserSharedAction))] -public abstract class UserSharedAction : MessageAction -{ - /// - /// Information about the user-shared content. - /// - public readonly UserShared UserShared; - - /// - protected UserSharedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - UserShared = Message.UserShared!; - } -} \ No newline at end of file diff --git a/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs b/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs index 2584718..2cd4552 100644 --- a/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs +++ b/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; using Telegram.Bot.Types; namespace Navigator.Configuration; @@ -48,7 +47,7 @@ private static async Task ParseTelegramUpdate(HttpRequest request) try { var reader = new StreamReader(request.Body); - return JsonConvert.DeserializeObject(await reader.ReadToEndAsync()) ?? throw new InvalidOperationException(); + return JsonSerializer.Deserialize(await reader.ReadToEndAsync()) ?? throw new InvalidOperationException(); } catch (Exception e) { diff --git a/src/Navigator/TelegramMiddleware.cs b/src/Navigator/TelegramMiddleware.cs index 4c4ea54..bfee47e 100644 --- a/src/Navigator/TelegramMiddleware.cs +++ b/src/Navigator/TelegramMiddleware.cs @@ -108,7 +108,6 @@ await _navigatorContextFactory.Supply(builder => MessageType.GeneralForumTopicHidden => nameof(GeneralForumTopicHiddenAction), MessageType.GeneralForumTopicUnhidden => nameof(GeneralForumTopicUnhiddenAction), MessageType.WriteAccessAllowed => nameof(WriteAccessAllowedAction), - MessageType.UserShared => nameof(UserSharedAction), MessageType.ChatShared => nameof(ChatSharedAction), _ => nameof(MessageAction) }, From 40acc3ec83ce56f983c15410fbe1ba12530b0f71 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Fri, 26 Jul 2024 22:48:28 +0200 Subject: [PATCH 05/66] feat: define first iteration of the new action type --- src/Navigator/Actions/Action.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/Navigator/Actions/Action.cs diff --git a/src/Navigator/Actions/Action.cs b/src/Navigator/Actions/Action.cs new file mode 100644 index 0000000..eedaa4d --- /dev/null +++ b/src/Navigator/Actions/Action.cs @@ -0,0 +1,18 @@ +using Navigator.Context; +using Navigator.Context.Accessor; + +namespace Navigator.Actions; + +public abstract record Action +{ + public readonly INavigatorContext Context; + + private Action(INavigatorContextAccessor navigatorContextAccessor) + { + Context = navigatorContextAccessor.NavigatorContext; + } + + public abstract Task CanHandleCurrentContext(); + + public abstract Task Handle(); +} \ No newline at end of file From 4636bf8c6998b66ec7f618b8af5a3e218ade2d8f Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Mon, 29 Jul 2024 20:56:24 +0200 Subject: [PATCH 06/66] feat: starting deleting some old code --- src/Navigator/Actions/Action.cs | 29 ++++++++--- src/Navigator/Actions/ActionHandler.cs | 52 ------------------- src/Navigator/Actions/ActionLauncher.cs | 33 ++++++------ src/Navigator/Actions/BaseAction.cs | 41 --------------- src/Navigator/Actions/IAction.cs | 15 ------ src/Navigator/Actions/IActionMiddleware.cs | 12 ----- .../Actions/ProviderAgnosticAction.cs | 20 ------- src/Navigator/Navigator.csproj | 1 - src/Navigator/ServiceCollectionExtensions.cs | 12 ++--- src/Sample/Actions/EchoAction.cs | 20 +++++-- src/Sample/Actions/EchoActionHandler.cs | 21 -------- src/Sample/Sample.csproj | 2 +- 12 files changed, 60 insertions(+), 198 deletions(-) delete mode 100644 src/Navigator/Actions/ActionHandler.cs delete mode 100644 src/Navigator/Actions/BaseAction.cs delete mode 100644 src/Navigator/Actions/IAction.cs delete mode 100644 src/Navigator/Actions/IActionMiddleware.cs delete mode 100644 src/Navigator/Actions/ProviderAgnosticAction.cs delete mode 100644 src/Sample/Actions/EchoActionHandler.cs diff --git a/src/Navigator/Actions/Action.cs b/src/Navigator/Actions/Action.cs index eedaa4d..60ae0a6 100644 --- a/src/Navigator/Actions/Action.cs +++ b/src/Navigator/Actions/Action.cs @@ -1,18 +1,35 @@ +using Navigator.Actions.Attributes; using Navigator.Context; using Navigator.Context.Accessor; namespace Navigator.Actions; +[ActionPriority(Actions.Priority.Default)] public abstract record Action { - public readonly INavigatorContext Context; + private readonly INavigatorContextAccessor _navigatorContextAccessor; + + protected INavigatorContext Context => _navigatorContextAccessor.NavigatorContext; + + public readonly DateTime Timestamp; - private Action(INavigatorContextAccessor navigatorContextAccessor) + protected Action(INavigatorContextAccessor navigatorContextAccessor) { - Context = navigatorContextAccessor.NavigatorContext; + _navigatorContextAccessor = navigatorContextAccessor; + Timestamp = DateTime.UtcNow; } - - public abstract Task CanHandleCurrentContext(); - public abstract Task Handle(); + public abstract bool CanHandleCurrentContext(CancellationToken cancellationToken = default); + + public abstract Task Handle(CancellationToken cancellationToken = default); + + protected static Status Success() + { + return new Status(true); + } + + protected static Status Error() + { + return new Status(false); + } } \ No newline at end of file diff --git a/src/Navigator/Actions/ActionHandler.cs b/src/Navigator/Actions/ActionHandler.cs deleted file mode 100644 index fd15aa1..0000000 --- a/src/Navigator/Actions/ActionHandler.cs +++ /dev/null @@ -1,52 +0,0 @@ -using MediatR; -using Navigator.Context; -using Navigator.Context.Accessor; - -namespace Navigator.Actions; - -/// -/// Implement to handle an action. -/// -/// -public abstract class ActionHandler : IRequestHandler where TAction : IAction -{ - /// - /// Context for the action. - /// - public readonly INavigatorContext Context; - - /// - /// Default constructor. - /// - /// - protected ActionHandler(INavigatorContextAccessor navigatorContextAccessor) - { - Context = navigatorContextAccessor.NavigatorContext; - } - - /// - /// Handles the action. - /// - /// - /// - /// - public abstract Task Handle(TAction action, CancellationToken cancellationToken); - - /// - /// Called when the action was handled successfully. - /// - /// - protected static Status Success() - { - return new Status(true); - } - - /// - /// Called when the action was not handled successfully. - /// - /// - protected static Status Error() - { - return new Status(false); - } -} \ No newline at end of file diff --git a/src/Navigator/Actions/ActionLauncher.cs b/src/Navigator/Actions/ActionLauncher.cs index 86c2663..d96360f 100644 --- a/src/Navigator/Actions/ActionLauncher.cs +++ b/src/Navigator/Actions/ActionLauncher.cs @@ -1,5 +1,4 @@ using System.Collections.Immutable; -using MediatR; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Navigator.Configuration; @@ -14,17 +13,16 @@ internal class ActionLauncher : IActionLauncher private readonly ILogger _logger; private readonly INavigatorContextAccessor _navigatorContextAccessor; private readonly IServiceProvider _serviceProvider; - private readonly ISender _sender; private readonly NavigatorOptions _navigatorOptions; private readonly ImmutableDictionary _actions; private readonly ImmutableDictionary _priorities; - public ActionLauncher(ILogger logger, NavigatorOptions navigatorOptions, INavigatorContextAccessor navigatorContextAccessor, IServiceProvider serviceProvider, ISender sender) + public ActionLauncher(ILogger logger, NavigatorOptions navigatorOptions, + INavigatorContextAccessor navigatorContextAccessor, IServiceProvider serviceProvider) { _logger = logger; _navigatorContextAccessor = navigatorContextAccessor; _serviceProvider = serviceProvider; - _sender = sender; _navigatorOptions = navigatorOptions; _actions = _navigatorOptions.RetrieveActions(); _priorities = _navigatorOptions.RetrievePriorities(); @@ -43,8 +41,9 @@ public async Task Launch() { await _navigatorContextAccessor.NavigatorContext.Client.SendChatActionAsync(chatId, ChatAction.Typing); } - - await _sender.Send(action); + + // TODO: propagate cancellation token + await action.Handle(CancellationToken.None); } catch (Exception e) { @@ -53,39 +52,39 @@ public async Task Launch() } } - private IEnumerable GetActions() + private IEnumerable GetActions() { if (string.IsNullOrWhiteSpace(_navigatorContextAccessor.NavigatorContext.ActionType)) { - return Array.Empty(); + return Array.Empty(); } var actions = _actions - .Where(a => - a.Key == _navigatorContextAccessor.NavigatorContext.ActionType || - a.Key == nameof(ProviderAgnosticAction)) - .ToImmutableList(); - + // .Where(a => + // a.Key == _navigatorContextAccessor.NavigatorContext.ActionType || + // a.Key == nameof(ProviderAgnosticAction)) + .ToImmutableList(); + if (_navigatorOptions.MultipleActionsUsageIsEnabled()) { return actions .SelectMany(groups => groups.Value) .SelectMany(actionType => _serviceProvider.GetServices(actionType) - .Select(action =>((IAction) action!, actionType.FullName))) + .Select(action => ((Action)action!, actionType.FullName))) .Where(a => a.Item1.CanHandleCurrentContext()) .OrderBy(a => _priorities.GetValueOrDefault(a.FullName ?? string.Empty, Priority.Default)) .Select(a => a.Item1) .AsEnumerable(); } - + var action = actions .SelectMany(groups => groups.Value) .SelectMany(actionType => _serviceProvider.GetServices(actionType) - .Select(action =>((IAction) action!, actionType.FullName))) + .Select(action => ((Action)action!, actionType.FullName))) .OrderBy(a => _priorities.GetValueOrDefault(a.FullName ?? string.Empty, Priority.Default)) .Select(a => a.Item1) .FirstOrDefault(a => a.CanHandleCurrentContext()); - return action is not null ? new[] {action} : Array.Empty(); + return action is not null ? new[] { action } : []; } } \ No newline at end of file diff --git a/src/Navigator/Actions/BaseAction.cs b/src/Navigator/Actions/BaseAction.cs deleted file mode 100644 index c47bd7b..0000000 --- a/src/Navigator/Actions/BaseAction.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context; -using Navigator.Context.Accessor; - -namespace Navigator.Actions; - -/// -/// Base action to use for any action. -/// -[ActionPriority(Actions.Priority.Default)] -public abstract class BaseAction : IAction -{ - private readonly INavigatorContextAccessor _navigatorContextAccessor; - - /// - /// Used to access inside the action. - /// - protected INavigatorContext Context => _navigatorContextAccessor.NavigatorContext; - - /// - /// Priority of the request. - /// - public virtual ushort Priority { get; protected set; } = Actions.Priority.Default; - - /// - /// Timestamp of the request on creation. - /// - public DateTime Timestamp { get; } - - /// - /// Default constructor for - /// - public BaseAction(INavigatorContextAccessor navigatorContextAccessor) - { - _navigatorContextAccessor = navigatorContextAccessor; - Timestamp = DateTime.UtcNow; - } - - /// - public abstract bool CanHandleCurrentContext(); -} \ No newline at end of file diff --git a/src/Navigator/Actions/IAction.cs b/src/Navigator/Actions/IAction.cs deleted file mode 100644 index 822533b..0000000 --- a/src/Navigator/Actions/IAction.cs +++ /dev/null @@ -1,15 +0,0 @@ -using MediatR; - -namespace Navigator.Actions; - -/// -/// Base contract for an action. -/// -public interface IAction : IRequest -{ - /// - /// This function must return true when the incoming update can be handled by this action. - /// - /// - bool CanHandleCurrentContext(); -} \ No newline at end of file diff --git a/src/Navigator/Actions/IActionMiddleware.cs b/src/Navigator/Actions/IActionMiddleware.cs deleted file mode 100644 index fec8344..0000000 --- a/src/Navigator/Actions/IActionMiddleware.cs +++ /dev/null @@ -1,12 +0,0 @@ -using MediatR; - -namespace Navigator.Actions; - -/// -/// Interface to implement middleware for actions. -/// -/// -/// -public interface IActionMiddleware : IPipelineBehavior where TAction : IAction -{ -} \ No newline at end of file diff --git a/src/Navigator/Actions/ProviderAgnosticAction.cs b/src/Navigator/Actions/ProviderAgnosticAction.cs deleted file mode 100644 index 4a30ebd..0000000 --- a/src/Navigator/Actions/ProviderAgnosticAction.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context; -using Navigator.Context.Accessor; - -namespace Navigator.Actions; - -/// -/// Base action for provider agnostic actions. -/// -[ActionType(nameof(ProviderAgnosticAction))] -public abstract class ProviderAgnosticAction : BaseAction -{ - /// - /// Default constructor. - /// - /// - protected ProviderAgnosticAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - } -} \ No newline at end of file diff --git a/src/Navigator/Navigator.csproj b/src/Navigator/Navigator.csproj index 76f6e33..a898fe2 100644 --- a/src/Navigator/Navigator.csproj +++ b/src/Navigator/Navigator.csproj @@ -27,7 +27,6 @@ - diff --git a/src/Navigator/ServiceCollectionExtensions.cs b/src/Navigator/ServiceCollectionExtensions.cs index eda29f5..5e91bf8 100644 --- a/src/Navigator/ServiceCollectionExtensions.cs +++ b/src/Navigator/ServiceCollectionExtensions.cs @@ -1,4 +1,3 @@ -using MediatR; using Microsoft.Extensions.DependencyInjection; using Navigator.Actions; using Navigator.Bundled.Extensions.Update; @@ -10,6 +9,7 @@ using Navigator.Extensions; using Navigator.Hosted; using Scrutor; +using Action = Navigator.Actions.Action; namespace Navigator; @@ -45,22 +45,20 @@ public static NavigatorConfiguration AddNavigator(this IServiceCollection servic services.AddScoped(); services.AddHostedService(); - - services.AddMediatR(navigatorBuilder.Options.GetActionsAssemblies()); - + services.Scan(scan => scan .FromAssemblies(navigatorBuilder.Options.GetActionsAssemblies()) - .AddClasses(classes => classes.AssignableTo()) + .AddClasses(classes => classes.AssignableTo()) .UsingRegistrationStrategy(RegistrationStrategy.Append) .AsSelf() .WithScopedLifetime()); navigatorBuilder.Options.RegisterActionsCore(services - .Where(descriptor => descriptor.ImplementationType?.IsAssignableTo(typeof(IAction)) ?? false) + .Where(descriptor => descriptor.ImplementationType?.IsAssignableTo(typeof(Action)) ?? false) .Select(descriptor => descriptor.ImplementationType!)); navigatorBuilder.Options.RegisterActionsPriorityCore(services - .Where(descriptor => descriptor.ImplementationType?.IsAssignableTo(typeof(IAction)) ?? false) + .Where(descriptor => descriptor.ImplementationType?.IsAssignableTo(typeof(Action)) ?? false) .Select(descriptor => descriptor.ImplementationType!)); navigatorBuilder.RegisterOrReplaceOptions(); diff --git a/src/Sample/Actions/EchoAction.cs b/src/Sample/Actions/EchoAction.cs index 7bae6fa..bf05500 100644 --- a/src/Sample/Actions/EchoAction.cs +++ b/src/Sample/Actions/EchoAction.cs @@ -1,17 +1,27 @@ -using Navigator.Bundled.Actions.Messages; +using System.Threading; +using System.Threading.Tasks; +using Navigator.Actions; +using Navigator.Bundled.Extensions.Update; using Navigator.Context.Accessor; -using Telegram.Bot.Types.Enums; +using Telegram.Bot; namespace Sample.Actions; -public class EchoAction : TextAction +public record EchoAction : Action { public EchoAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) { } + + public override bool CanHandleCurrentContext(CancellationToken cancellationToken = default) + { + return !string.IsNullOrWhiteSpace(Context.GetUpdate().Message!.Text); + } - public override bool CanHandleCurrentContext() + public override async Task Handle(CancellationToken cancellationToken = default) { - return !string.IsNullOrWhiteSpace(Text); + await Context.Client.SendTextMessageAsync(action.ChatId, action.Text, cancellationToken: cancellationToken); + + return Success(); } } \ No newline at end of file diff --git a/src/Sample/Actions/EchoActionHandler.cs b/src/Sample/Actions/EchoActionHandler.cs deleted file mode 100644 index a95df7c..0000000 --- a/src/Sample/Actions/EchoActionHandler.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Navigator.Actions; -using Navigator.Context.Accessor; -using Telegram.Bot; - -namespace Sample.Actions; - -public class EchoActionHandler : ActionHandler -{ - public EchoActionHandler(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - } - - public override async Task Handle(EchoAction action, CancellationToken cancellationToken) - { - await Context.Client.SendTextMessageAsync(action.ChatId, action.Text, cancellationToken: cancellationToken); - - return Success(); - } -} \ No newline at end of file diff --git a/src/Sample/Sample.csproj b/src/Sample/Sample.csproj index 5e1f1ee..3fdf033 100644 --- a/src/Sample/Sample.csproj +++ b/src/Sample/Sample.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable false From b1d06583adc4fce5219e211d458f32ab353079cb Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Mon, 29 Jul 2024 23:55:22 +0200 Subject: [PATCH 07/66] feat: define basic INavigatorBotBuilder --- src/Navigator/Configuration/INavigatorBotBuilder.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/Navigator/Configuration/INavigatorBotBuilder.cs diff --git a/src/Navigator/Configuration/INavigatorBotBuilder.cs b/src/Navigator/Configuration/INavigatorBotBuilder.cs new file mode 100644 index 0000000..48186af --- /dev/null +++ b/src/Navigator/Configuration/INavigatorBotBuilder.cs @@ -0,0 +1,10 @@ +using Navigator.Context; +using Telegram.Bot.Types; + +namespace Navigator.Configuration; + +public interface INavigatorBotBuilder +{ + public NavigatorBotBuilder OnUpdate(Func> condition, Action action); + public NavigatorBotBuilder OnUpdate(Func condition, Action action); +} \ No newline at end of file From 55e54f0307449e31d0ad0b8decd5ff7be8dbccb1 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Mon, 29 Jul 2024 23:57:01 +0200 Subject: [PATCH 08/66] feat: start implementing basic NavigatorBotBuilder --- .../Configuration/NavigatorBotBuilder.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/Navigator/Configuration/NavigatorBotBuilder.cs diff --git a/src/Navigator/Configuration/NavigatorBotBuilder.cs b/src/Navigator/Configuration/NavigatorBotBuilder.cs new file mode 100644 index 0000000..449b115 --- /dev/null +++ b/src/Navigator/Configuration/NavigatorBotBuilder.cs @@ -0,0 +1,20 @@ +using Navigator.Context; +using Telegram.Bot.Types; + +namespace Navigator.Configuration; + +public class NavigatorBotBuilder : INavigatorBotBuilder +{ + protected readonly List Actions = []; + public NavigatorBotBuilder OnUpdate(Func> condition, Action action) + { + Actions.Add(new BotAction(condition, action)); + + return this; + } + + public NavigatorBotBuilder OnUpdate(Func condition, Action action) + { + throw new NotImplementedException(); + } +} \ No newline at end of file From 41a1169f966cdd00cdce408cb6e481fc515877d8 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Tue, 30 Jul 2024 14:33:46 +0200 Subject: [PATCH 09/66] feat: add StrategyBuilder --- src/Navigator/Actions/BotAction.cs | 57 +++++++++++++++++++ src/Navigator/Builder/IBotStrategyBuilder.cs | 14 +++++ src/Navigator/Builder/INavigatorBotBuilder.cs | 8 +++ src/Navigator/Builder/NavigatorBotBuilder.cs | 32 +++++++++++ .../ApplicationBuilderExtensions.cs | 16 ++++++ .../Configuration/INavigatorBotBuilder.cs | 10 ---- .../Configuration/NavigatorBotBuilder.cs | 20 ------- src/Sample/Program.cs | 11 ++++ 8 files changed, 138 insertions(+), 30 deletions(-) create mode 100644 src/Navigator/Actions/BotAction.cs create mode 100644 src/Navigator/Builder/IBotStrategyBuilder.cs create mode 100644 src/Navigator/Builder/INavigatorBotBuilder.cs create mode 100644 src/Navigator/Builder/NavigatorBotBuilder.cs create mode 100644 src/Navigator/Configuration/ApplicationBuilderExtensions.cs delete mode 100644 src/Navigator/Configuration/INavigatorBotBuilder.cs delete mode 100644 src/Navigator/Configuration/NavigatorBotBuilder.cs diff --git a/src/Navigator/Actions/BotAction.cs b/src/Navigator/Actions/BotAction.cs new file mode 100644 index 0000000..33f70b2 --- /dev/null +++ b/src/Navigator/Actions/BotAction.cs @@ -0,0 +1,57 @@ +using Navigator.Context; +using Telegram.Bot.Types; + +namespace Navigator.Configuration; + +public record BotAction +{ + private Func>? ConditionAsync { get; } = default; + private Func? Condition { get; } = default; + + private Func? HandlerAsync { get; } = default; + private Action? Handler { get; } = default; + + /// + /// Constructor for condition and handler being both async delegates. + /// + /// + /// + public BotAction(Func> condition, Func handler) + { + ConditionAsync = condition; + HandlerAsync = handler; + } + + /// + /// Constructor for an async condition delegate with a sync handler delegate. + /// + /// + /// + public BotAction(Func> condition, Action handler) + { + ConditionAsync = condition; + Handler = handler; + } + + /// + /// Constructor for a sync condition delegate with an async handler delegate. + /// + /// + /// + public BotAction(Func condition, Func handler) + { + Condition = condition; + HandlerAsync = handler; + } + + /// + /// Constructor for condition and handler being both sync delegates. + /// + /// + /// + public BotAction(Func condition, Action handler) + { + Condition = condition; + Handler = handler; + } +} \ No newline at end of file diff --git a/src/Navigator/Builder/IBotStrategyBuilder.cs b/src/Navigator/Builder/IBotStrategyBuilder.cs new file mode 100644 index 0000000..e067bcc --- /dev/null +++ b/src/Navigator/Builder/IBotStrategyBuilder.cs @@ -0,0 +1,14 @@ +using Navigator.Context; +using Telegram.Bot.Types; + +namespace Navigator.Builder; + +public interface IBotStrategyBuilder +{ + public IBotActionBuilder OnUpdate(Func> condition, Func handler); + public IBotActionBuilder OnUpdate(Func> condition, Action handler); + public IBotActionBuilder OnUpdate(Func condition, Func handler); + public IBotActionBuilder OnUpdate(Func condition, Action handler); + + // public NavigatorBotBuilder OnCommand(string command, Func action); +} \ No newline at end of file diff --git a/src/Navigator/Builder/INavigatorBotBuilder.cs b/src/Navigator/Builder/INavigatorBotBuilder.cs new file mode 100644 index 0000000..dc8e261 --- /dev/null +++ b/src/Navigator/Builder/INavigatorBotBuilder.cs @@ -0,0 +1,8 @@ +using Navigator.Context; +using Telegram.Bot.Types; + +namespace Navigator.Builder; + +public interface IBotActionBuilder +{ +} \ No newline at end of file diff --git a/src/Navigator/Builder/NavigatorBotBuilder.cs b/src/Navigator/Builder/NavigatorBotBuilder.cs new file mode 100644 index 0000000..fa13150 --- /dev/null +++ b/src/Navigator/Builder/NavigatorBotBuilder.cs @@ -0,0 +1,32 @@ +using Navigator.Configuration; +using Navigator.Context; +using Telegram.Bot.Types; + +namespace Navigator.Builder; + +public class BotStrategyBuilder : IBotStrategyBuilder +{ + protected readonly BotAction[] Actions = []; + + public IBotActionBuilder OnUpdate(Func> condition, Func handler) + { + Actions.Add(new BotAction(condition, handler)); + + return + } + + public IBotActionBuilder OnUpdate(Func> condition, Action handler) + { + throw new NotImplementedException(); + } + + public IBotActionBuilder OnUpdate(Func condition, Func handler) + { + throw new NotImplementedException(); + } + + public IBotActionBuilder OnUpdate(Func condition, Action handler) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/Navigator/Configuration/ApplicationBuilderExtensions.cs b/src/Navigator/Configuration/ApplicationBuilderExtensions.cs new file mode 100644 index 0000000..e70f25e --- /dev/null +++ b/src/Navigator/Configuration/ApplicationBuilderExtensions.cs @@ -0,0 +1,16 @@ +using Microsoft.AspNetCore.Builder; +using Action = Navigator.Actions.Action; + +namespace Navigator.Configuration; + +/// +/// Navigator extensions for +/// +public static class ApplicationBuilderExtensions +{ + public static INavigatorBotBuilder GetBot(this IApplicationBuilder builder) + { + return new NavigatorBotBuilder(); + } + +} \ No newline at end of file diff --git a/src/Navigator/Configuration/INavigatorBotBuilder.cs b/src/Navigator/Configuration/INavigatorBotBuilder.cs deleted file mode 100644 index 48186af..0000000 --- a/src/Navigator/Configuration/INavigatorBotBuilder.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Navigator.Context; -using Telegram.Bot.Types; - -namespace Navigator.Configuration; - -public interface INavigatorBotBuilder -{ - public NavigatorBotBuilder OnUpdate(Func> condition, Action action); - public NavigatorBotBuilder OnUpdate(Func condition, Action action); -} \ No newline at end of file diff --git a/src/Navigator/Configuration/NavigatorBotBuilder.cs b/src/Navigator/Configuration/NavigatorBotBuilder.cs deleted file mode 100644 index 449b115..0000000 --- a/src/Navigator/Configuration/NavigatorBotBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Navigator.Context; -using Telegram.Bot.Types; - -namespace Navigator.Configuration; - -public class NavigatorBotBuilder : INavigatorBotBuilder -{ - protected readonly List Actions = []; - public NavigatorBotBuilder OnUpdate(Func> condition, Action action) - { - Actions.Add(new BotAction(condition, action)); - - return this; - } - - public NavigatorBotBuilder OnUpdate(Func condition, Action action) - { - throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/src/Sample/Program.cs b/src/Sample/Program.cs index 1f78fb4..39cdf6c 100644 --- a/src/Sample/Program.cs +++ b/src/Sample/Program.cs @@ -1,8 +1,10 @@ using System; +using System.Linq; using Incremental.Common.Configuration; using Microsoft.AspNetCore.Builder; using Navigator; using Navigator.Configuration; +using Telegram.Bot; namespace Sample; @@ -24,6 +26,15 @@ public static void Main(string[] args) var app = builder.Build(); + var bot = app.GetBot(); + + // bot.OnCommand("join", async (ctx, parameters) => + // { + // var result = string.Join(' ', parameters); + // + // await ctx.Client.SendTextMessageAsync(ctx.Conversation.Chat!.Id, result); + // } ); + app.MapNavigator(); app.Run(); From f2e612667cdae7d704038daca3f69011cf21a898 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 31 Jul 2024 11:43:49 +0200 Subject: [PATCH 10/66] refactor: correct namespace --- src/Navigator/Actions/BotAction.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Navigator/Actions/BotAction.cs b/src/Navigator/Actions/BotAction.cs index 33f70b2..f6b3f74 100644 --- a/src/Navigator/Actions/BotAction.cs +++ b/src/Navigator/Actions/BotAction.cs @@ -1,7 +1,7 @@ using Navigator.Context; using Telegram.Bot.Types; -namespace Navigator.Configuration; +namespace Navigator.Actions; public record BotAction { From 7fdde3a9790e703e6f2bdc87f7a74c63cad5591d Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 31 Jul 2024 12:40:35 +0200 Subject: [PATCH 11/66] feat: make botName optional using default value --- src/Navigator/Telegram/TelegramUpdateExtensions.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Navigator/Telegram/TelegramUpdateExtensions.cs b/src/Navigator/Telegram/TelegramUpdateExtensions.cs index 28bc8f7..b01c293 100644 --- a/src/Navigator/Telegram/TelegramUpdateExtensions.cs +++ b/src/Navigator/Telegram/TelegramUpdateExtensions.cs @@ -8,7 +8,7 @@ namespace Navigator.Telegram; internal static class TelegramUpdateExtensions { - public static string? ExtractCommand(this Message message, string? botName) + public static string? ExtractCommand(this Message message, string? botName = default) { if (message.Entities?.First().Type != MessageEntityType.BotCommand) return default; @@ -79,7 +79,6 @@ public static Conversation GetConversation(this Update update) CanJoinGroups = rawUser.CanJoinGroups, CanReadAllGroupMessages = rawUser.CanReadAllGroupMessages, SupportsInlineQueries = rawUser.SupportsInlineQueries - } : new Entities.User(rawUser.Id, rawUser.FirstName) { From 0693ec6195e26dc88244a919d5a5d955de54c07f Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 31 Jul 2024 12:41:01 +0200 Subject: [PATCH 12/66] refactor: use the correct type --- src/Navigator/Configuration/ApplicationBuilderExtensions.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Navigator/Configuration/ApplicationBuilderExtensions.cs b/src/Navigator/Configuration/ApplicationBuilderExtensions.cs index e70f25e..bbb02ab 100644 --- a/src/Navigator/Configuration/ApplicationBuilderExtensions.cs +++ b/src/Navigator/Configuration/ApplicationBuilderExtensions.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Builder; +using Navigator.Builder; using Action = Navigator.Actions.Action; namespace Navigator.Configuration; @@ -8,9 +9,9 @@ namespace Navigator.Configuration; /// public static class ApplicationBuilderExtensions { - public static INavigatorBotBuilder GetBot(this IApplicationBuilder builder) + public static IBotActionCatalogBuilder GetBot(this IApplicationBuilder builder) { - return new NavigatorBotBuilder(); + return new BotActionCatalogBuilder(); } } \ No newline at end of file From 710363875f7d929fb3a63024770ea5be89f0928c Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 31 Jul 2024 12:41:25 +0200 Subject: [PATCH 13/66] feat: experiment with delegate execution --- src/Navigator/Actions/BotAction.cs | 63 ++++++++++++------------------ 1 file changed, 24 insertions(+), 39 deletions(-) diff --git a/src/Navigator/Actions/BotAction.cs b/src/Navigator/Actions/BotAction.cs index f6b3f74..f67340f 100644 --- a/src/Navigator/Actions/BotAction.cs +++ b/src/Navigator/Actions/BotAction.cs @@ -5,53 +5,38 @@ namespace Navigator.Actions; public record BotAction { - private Func>? ConditionAsync { get; } = default; - private Func? Condition { get; } = default; - - private Func? HandlerAsync { get; } = default; - private Action? Handler { get; } = default; + // private Func>? ConditionAsync { get; } = default; + // private Func? Condition { get; } = default; + // + // private Func? HandlerAsync { get; } = default; + // private Action? Handler { get; } = default; - /// - /// Constructor for condition and handler being both async delegates. - /// - /// - /// - public BotAction(Func> condition, Func handler) - { - ConditionAsync = condition; - HandlerAsync = handler; - } + private static Delegate Condition { get; set; } + private static Delegate Handler { get; set; } - /// - /// Constructor for an async condition delegate with a sync handler delegate. - /// - /// - /// - public BotAction(Func> condition, Action handler) + public BotAction(Delegate condition, Delegate handler) { - ConditionAsync = condition; + Condition = condition; Handler = handler; } - - /// - /// Constructor for a sync condition delegate with an async handler delegate. - /// - /// - /// - public BotAction(Func condition, Func handler) + + public async Task ExecuteCondition(params object[] args) { - Condition = condition; - HandlerAsync = handler; + var result = Handler.DynamicInvoke(args); + + if (result is Task task) + { + await task; + } } - /// - /// Constructor for condition and handler being both sync delegates. - /// - /// - /// - public BotAction(Func condition, Action handler) + public async Task ExecuteHandler(params object[] args) { - Condition = condition; - Handler = handler; + var result = Handler.DynamicInvoke(args); + + if (result is Task task) + { + await task; + } } } \ No newline at end of file From 2508b56507924594c22d7ac3879bcca227534040 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 31 Jul 2024 12:42:42 +0200 Subject: [PATCH 14/66] feat: implement basic BotActionBuilder --- src/Navigator/Builder/BotActionBuilder.cs | 16 ++++++++++++++++ src/Navigator/Builder/INavigatorBotBuilder.cs | 8 -------- 2 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 src/Navigator/Builder/BotActionBuilder.cs delete mode 100644 src/Navigator/Builder/INavigatorBotBuilder.cs diff --git a/src/Navigator/Builder/BotActionBuilder.cs b/src/Navigator/Builder/BotActionBuilder.cs new file mode 100644 index 0000000..d1f3c7d --- /dev/null +++ b/src/Navigator/Builder/BotActionBuilder.cs @@ -0,0 +1,16 @@ +using Navigator.Actions; +using Navigator.Configuration; +using Navigator.Context; +using Telegram.Bot.Types; + +namespace Navigator.Builder; + +public class BotActionBuilder : IBotActionBuilder +{ + protected BotAction BotAction { get; set; } + + public BotActionBuilder(BotAction botAction) + { + BotAction = botAction; + } +} \ No newline at end of file diff --git a/src/Navigator/Builder/INavigatorBotBuilder.cs b/src/Navigator/Builder/INavigatorBotBuilder.cs deleted file mode 100644 index dc8e261..0000000 --- a/src/Navigator/Builder/INavigatorBotBuilder.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Navigator.Context; -using Telegram.Bot.Types; - -namespace Navigator.Builder; - -public interface IBotActionBuilder -{ -} \ No newline at end of file From 0335bbafc335d0a77464f3e70ce8f8cb0d119bb0 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 31 Jul 2024 12:42:58 +0200 Subject: [PATCH 15/66] feat: add more methods to IBotActionCatalogBuilder --- .../{IBotStrategyBuilder.cs => IBotActionCatalogBuilder.cs} | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) rename src/Navigator/Builder/{IBotStrategyBuilder.cs => IBotActionCatalogBuilder.cs} (67%) diff --git a/src/Navigator/Builder/IBotStrategyBuilder.cs b/src/Navigator/Builder/IBotActionCatalogBuilder.cs similarity index 67% rename from src/Navigator/Builder/IBotStrategyBuilder.cs rename to src/Navigator/Builder/IBotActionCatalogBuilder.cs index e067bcc..d8182fc 100644 --- a/src/Navigator/Builder/IBotStrategyBuilder.cs +++ b/src/Navigator/Builder/IBotActionCatalogBuilder.cs @@ -3,12 +3,16 @@ namespace Navigator.Builder; -public interface IBotStrategyBuilder +public interface IBotActionCatalogBuilder { public IBotActionBuilder OnUpdate(Func> condition, Func handler); public IBotActionBuilder OnUpdate(Func> condition, Action handler); public IBotActionBuilder OnUpdate(Func condition, Func handler); public IBotActionBuilder OnUpdate(Func condition, Action handler); + public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler); + public IBotActionBuilder OnUpdate(Func> condition, Delegate handler); + public IBotActionBuilder OnUpdate(Func condition, Delegate handler); + // public NavigatorBotBuilder OnCommand(string command, Func action); } \ No newline at end of file From fe8ec67879b72bca5b63566c04543aac9fceacbc Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 31 Jul 2024 12:48:38 +0200 Subject: [PATCH 16/66] refactor: simplify IBotActionCatalogBuilder more specific methods can be added with extensions --- .../Builder/BotActionCatalogBuilder.cs | 25 +++++++++++++++ .../Builder/IBotActionCatalogBuilder.cs | 14 ++++---- src/Navigator/Builder/NavigatorBotBuilder.cs | 32 ------------------- 3 files changed, 32 insertions(+), 39 deletions(-) create mode 100644 src/Navigator/Builder/BotActionCatalogBuilder.cs delete mode 100644 src/Navigator/Builder/NavigatorBotBuilder.cs diff --git a/src/Navigator/Builder/BotActionCatalogBuilder.cs b/src/Navigator/Builder/BotActionCatalogBuilder.cs new file mode 100644 index 0000000..0165e9a --- /dev/null +++ b/src/Navigator/Builder/BotActionCatalogBuilder.cs @@ -0,0 +1,25 @@ +using Navigator.Actions; +using Navigator.Context; +using Telegram.Bot.Types; + +namespace Navigator.Builder; + +public class BotActionCatalogBuilder : IBotActionCatalogBuilder +{ + protected Dictionary Actions = []; + protected Dictionary> ConditionInputTypesByAction = []; + protected Dictionary> HandlerInputTypesByAction = []; + + public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler) + { + var id = Guid.NewGuid(); + var action = new BotAction(condition, handler); + + Actions.Add(id, action); + + ConditionInputTypesByAction.Add(id, condition.Method.GetParameters().Select(a => a.ParameterType)); + HandlerInputTypesByAction.Add(id, handler.Method.GetParameters().Select(a => a.ParameterType)); + + return new BotActionBuilder(action); + } +} \ No newline at end of file diff --git a/src/Navigator/Builder/IBotActionCatalogBuilder.cs b/src/Navigator/Builder/IBotActionCatalogBuilder.cs index d8182fc..84de21e 100644 --- a/src/Navigator/Builder/IBotActionCatalogBuilder.cs +++ b/src/Navigator/Builder/IBotActionCatalogBuilder.cs @@ -5,14 +5,14 @@ namespace Navigator.Builder; public interface IBotActionCatalogBuilder { - public IBotActionBuilder OnUpdate(Func> condition, Func handler); - public IBotActionBuilder OnUpdate(Func> condition, Action handler); - public IBotActionBuilder OnUpdate(Func condition, Func handler); - public IBotActionBuilder OnUpdate(Func condition, Action handler); public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler); - public IBotActionBuilder OnUpdate(Func> condition, Delegate handler); - public IBotActionBuilder OnUpdate(Func condition, Delegate handler); + // public IBotActionBuilder OnUpdate(Func> condition, Delegate handler); + // public IBotActionBuilder OnUpdate(Func> condition, Action handler); + // public IBotActionBuilder OnUpdate(Func> condition, Func handler); + // public IBotActionBuilder OnUpdate(Func condition, Delegate handler); + // public IBotActionBuilder OnUpdate(Func condition, Action handler); + // public IBotActionBuilder OnUpdate(Func condition, Func handler); + - // public NavigatorBotBuilder OnCommand(string command, Func action); } \ No newline at end of file diff --git a/src/Navigator/Builder/NavigatorBotBuilder.cs b/src/Navigator/Builder/NavigatorBotBuilder.cs deleted file mode 100644 index fa13150..0000000 --- a/src/Navigator/Builder/NavigatorBotBuilder.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Navigator.Configuration; -using Navigator.Context; -using Telegram.Bot.Types; - -namespace Navigator.Builder; - -public class BotStrategyBuilder : IBotStrategyBuilder -{ - protected readonly BotAction[] Actions = []; - - public IBotActionBuilder OnUpdate(Func> condition, Func handler) - { - Actions.Add(new BotAction(condition, handler)); - - return - } - - public IBotActionBuilder OnUpdate(Func> condition, Action handler) - { - throw new NotImplementedException(); - } - - public IBotActionBuilder OnUpdate(Func condition, Func handler) - { - throw new NotImplementedException(); - } - - public IBotActionBuilder OnUpdate(Func condition, Action handler) - { - throw new NotImplementedException(); - } -} \ No newline at end of file From 9ecece0032f118786a07732c88dcc9d8e36eff43 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 31 Jul 2024 13:13:59 +0200 Subject: [PATCH 17/66] feat: update BotActionBuilder with public property BotAction --- src/Navigator/Builder/BotActionBuilder.cs | 2 +- src/Navigator/Builder/IBotActionBuilder.cs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 src/Navigator/Builder/IBotActionBuilder.cs diff --git a/src/Navigator/Builder/BotActionBuilder.cs b/src/Navigator/Builder/BotActionBuilder.cs index d1f3c7d..e1e66fa 100644 --- a/src/Navigator/Builder/BotActionBuilder.cs +++ b/src/Navigator/Builder/BotActionBuilder.cs @@ -7,7 +7,7 @@ namespace Navigator.Builder; public class BotActionBuilder : IBotActionBuilder { - protected BotAction BotAction { get; set; } + public BotAction BotAction { get; set; } public BotActionBuilder(BotAction botAction) { diff --git a/src/Navigator/Builder/IBotActionBuilder.cs b/src/Navigator/Builder/IBotActionBuilder.cs new file mode 100644 index 0000000..48655e5 --- /dev/null +++ b/src/Navigator/Builder/IBotActionBuilder.cs @@ -0,0 +1,8 @@ +using Navigator.Actions; + +namespace Navigator.Builder; + +public interface IBotActionBuilder +{ + public BotAction BotAction { get; set; } +} \ No newline at end of file From efad91ade61733c0c6e3c5fa2062b7ecbb10be0a Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 31 Jul 2024 13:14:35 +0200 Subject: [PATCH 18/66] feat: add BotAction related properties to IBotActionCatalogBuilder as public --- src/Navigator/Builder/IBotActionCatalogBuilder.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Navigator/Builder/IBotActionCatalogBuilder.cs b/src/Navigator/Builder/IBotActionCatalogBuilder.cs index 84de21e..78bb214 100644 --- a/src/Navigator/Builder/IBotActionCatalogBuilder.cs +++ b/src/Navigator/Builder/IBotActionCatalogBuilder.cs @@ -1,10 +1,17 @@ +using Navigator.Actions; using Navigator.Context; using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; namespace Navigator.Builder; public interface IBotActionCatalogBuilder { + public Dictionary Actions { get; } + public Dictionary> ConditionInputTypesByAction { get; } + public Dictionary> HandlerInputTypesByAction { get; } + public Dictionary ActionTypeByAction { get; } + public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler); // public IBotActionBuilder OnUpdate(Func> condition, Delegate handler); // public IBotActionBuilder OnUpdate(Func> condition, Action handler); From 894aea7d57616a5b9c83d45c1b3d8565289d6098 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 31 Jul 2024 13:15:04 +0200 Subject: [PATCH 19/66] refactor: make BotAction related properties public, following interface changes --- src/Navigator/Builder/BotActionCatalogBuilder.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Navigator/Builder/BotActionCatalogBuilder.cs b/src/Navigator/Builder/BotActionCatalogBuilder.cs index 0165e9a..5b9f354 100644 --- a/src/Navigator/Builder/BotActionCatalogBuilder.cs +++ b/src/Navigator/Builder/BotActionCatalogBuilder.cs @@ -1,14 +1,16 @@ using Navigator.Actions; using Navigator.Context; using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; namespace Navigator.Builder; public class BotActionCatalogBuilder : IBotActionCatalogBuilder { - protected Dictionary Actions = []; - protected Dictionary> ConditionInputTypesByAction = []; - protected Dictionary> HandlerInputTypesByAction = []; + public Dictionary Actions { get; } = []; + public Dictionary> ConditionInputTypesByAction { get; } = []; + public Dictionary> HandlerInputTypesByAction { get; } = []; + public Dictionary ActionTypeByAction { get; } = []; public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler) { From a06a0d7f94e18fd9c8552fa7d84180cecdddfe17 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 31 Jul 2024 13:17:19 +0200 Subject: [PATCH 20/66] feat: add storage of action type per action --- src/Navigator/Builder/BotActionCatalogBuilder.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Navigator/Builder/BotActionCatalogBuilder.cs b/src/Navigator/Builder/BotActionCatalogBuilder.cs index 5b9f354..dbf3d80 100644 --- a/src/Navigator/Builder/BotActionCatalogBuilder.cs +++ b/src/Navigator/Builder/BotActionCatalogBuilder.cs @@ -22,6 +22,8 @@ public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler) ConditionInputTypesByAction.Add(id, condition.Method.GetParameters().Select(a => a.ParameterType)); HandlerInputTypesByAction.Add(id, handler.Method.GetParameters().Select(a => a.ParameterType)); + ActionTypeByAction.Add(id, $"{typeof(UpdateType)}.{nameof(UpdateType.Unknown)}"); + return new BotActionBuilder(action); } } \ No newline at end of file From 1a34110a411922563b60f6e5e945919353798eb9 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 31 Jul 2024 13:24:56 +0200 Subject: [PATCH 21/66] refactor: add options to builder and simplify. --- src/Navigator/Builder/BotActionBuilder.cs | 3 + .../Builder/BotActionBuilderOptions.cs | 60 +++++++++++++++++++ .../Builder/BotActionCatalogBuilder.cs | 17 ++---- src/Navigator/Builder/IBotActionBuilder.cs | 4 +- .../Builder/IBotActionCatalogBuilder.cs | 5 -- .../IBotActionCatalogBuilderExtensions.cs | 19 ++++++ 6 files changed, 90 insertions(+), 18 deletions(-) create mode 100644 src/Navigator/Builder/BotActionBuilderOptions.cs create mode 100644 src/Navigator/Builder/IBotActionCatalogBuilderExtensions.cs diff --git a/src/Navigator/Builder/BotActionBuilder.cs b/src/Navigator/Builder/BotActionBuilder.cs index e1e66fa..dee451d 100644 --- a/src/Navigator/Builder/BotActionBuilder.cs +++ b/src/Navigator/Builder/BotActionBuilder.cs @@ -9,8 +9,11 @@ public class BotActionBuilder : IBotActionBuilder { public BotAction BotAction { get; set; } + public BotActionBuilderOptions Options { get; } + public BotActionBuilder(BotAction botAction) { BotAction = botAction; + Options = new BotActionBuilderOptions(); } } \ No newline at end of file diff --git a/src/Navigator/Builder/BotActionBuilderOptions.cs b/src/Navigator/Builder/BotActionBuilderOptions.cs new file mode 100644 index 0000000..3c74c07 --- /dev/null +++ b/src/Navigator/Builder/BotActionBuilderOptions.cs @@ -0,0 +1,60 @@ +namespace Navigator.Configuration; + +/// +public class BotActionBuilderOptions +{ + private readonly Dictionary _options; + + /// + /// Default constructor. + /// + public BotActionBuilderOptions() + { + _options = new Dictionary(); + } + + public bool TryRegisterOption(string key, object option) + { + return _options.TryAdd(key, option); + } + + public void ForceRegisterOption(string key, object option) + { + _options.Remove(key); + + TryRegisterOption(key, option); + } + + public TType? RetrieveOption(string key) + { + if (_options.TryGetValue(key, out var option)) + { + return (TType) option; + } + + return default; + } + + public Dictionary RetrieveAllOptions() + { + return _options; + } + + public void Import(Dictionary options, bool overwrite = false) + { + if (overwrite) + { + foreach (var (key, option) in options) + { + ForceRegisterOption(key, option); + } + + return; + } + + foreach (var (key, option) in options) + { + TryRegisterOption(key, option); + } + } +} \ No newline at end of file diff --git a/src/Navigator/Builder/BotActionCatalogBuilder.cs b/src/Navigator/Builder/BotActionCatalogBuilder.cs index dbf3d80..28cd8b1 100644 --- a/src/Navigator/Builder/BotActionCatalogBuilder.cs +++ b/src/Navigator/Builder/BotActionCatalogBuilder.cs @@ -1,4 +1,5 @@ using Navigator.Actions; +using Navigator.Configuration; using Navigator.Context; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -7,23 +8,15 @@ namespace Navigator.Builder; public class BotActionCatalogBuilder : IBotActionCatalogBuilder { - public Dictionary Actions { get; } = []; - public Dictionary> ConditionInputTypesByAction { get; } = []; - public Dictionary> HandlerInputTypesByAction { get; } = []; - public Dictionary ActionTypeByAction { get; } = []; + public Dictionary Actions { get; } = []; public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler) { var id = Guid.NewGuid(); - var action = new BotAction(condition, handler); + var actionBuilder = new BotActionBuilder(new BotAction(condition, handler)); - Actions.Add(id, action); + Actions.Add(id, actionBuilder); - ConditionInputTypesByAction.Add(id, condition.Method.GetParameters().Select(a => a.ParameterType)); - HandlerInputTypesByAction.Add(id, handler.Method.GetParameters().Select(a => a.ParameterType)); - - ActionTypeByAction.Add(id, $"{typeof(UpdateType)}.{nameof(UpdateType.Unknown)}"); - - return new BotActionBuilder(action); + return actionBuilder; } } \ No newline at end of file diff --git a/src/Navigator/Builder/IBotActionBuilder.cs b/src/Navigator/Builder/IBotActionBuilder.cs index 48655e5..1335784 100644 --- a/src/Navigator/Builder/IBotActionBuilder.cs +++ b/src/Navigator/Builder/IBotActionBuilder.cs @@ -1,8 +1,10 @@ using Navigator.Actions; +using Navigator.Configuration; namespace Navigator.Builder; public interface IBotActionBuilder { - public BotAction BotAction { get; set; } + public BotAction BotAction { get; } + public BotActionBuilderOptions Options { get; } } \ No newline at end of file diff --git a/src/Navigator/Builder/IBotActionCatalogBuilder.cs b/src/Navigator/Builder/IBotActionCatalogBuilder.cs index 78bb214..7c7a224 100644 --- a/src/Navigator/Builder/IBotActionCatalogBuilder.cs +++ b/src/Navigator/Builder/IBotActionCatalogBuilder.cs @@ -7,11 +7,6 @@ namespace Navigator.Builder; public interface IBotActionCatalogBuilder { - public Dictionary Actions { get; } - public Dictionary> ConditionInputTypesByAction { get; } - public Dictionary> HandlerInputTypesByAction { get; } - public Dictionary ActionTypeByAction { get; } - public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler); // public IBotActionBuilder OnUpdate(Func> condition, Delegate handler); // public IBotActionBuilder OnUpdate(Func> condition, Action handler); diff --git a/src/Navigator/Builder/IBotActionCatalogBuilderExtensions.cs b/src/Navigator/Builder/IBotActionCatalogBuilderExtensions.cs new file mode 100644 index 0000000..6dcbb0b --- /dev/null +++ b/src/Navigator/Builder/IBotActionCatalogBuilderExtensions.cs @@ -0,0 +1,19 @@ +using Navigator.Telegram; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; + +namespace Navigator.Builder; + +public static class IBotActionCatalogBuilderExtensions +{ + public static IBotActionBuilder OnCommand(this IBotActionCatalogBuilder builder, string command, Delegate handler) + { + var actionBuilder = builder.OnUpdate((Update update) => update.Message?.ExtractCommand() == command, handler); + + var id = builder.Actions.FirstOrDefault(pair => pair.Value == actionBuilder.BotAction).Key; + + builder.ActionTypeByAction[id] = $"{typeof(MessageEntityType)}.{nameof(MessageEntityType.BotCommand)}"; + + return actionBuilder; + } +} \ No newline at end of file From a6d632f3eec724900004c5ac2374ace007afb023 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Fri, 9 Aug 2024 12:16:09 +0200 Subject: [PATCH 22/66] feat: update IBotActionCatalogBuilder & IBotActionCatalogBuilderExtensions Add Build method, and example OnCommand method. --- .../{Builder => Catalog}/IBotActionCatalogBuilder.cs | 9 ++++----- .../IBotActionCatalogBuilderExtensions.cs | 7 ++----- 2 files changed, 6 insertions(+), 10 deletions(-) rename src/Navigator/{Builder => Catalog}/IBotActionCatalogBuilder.cs (86%) rename src/Navigator/{Builder => Catalog}/IBotActionCatalogBuilderExtensions.cs (63%) diff --git a/src/Navigator/Builder/IBotActionCatalogBuilder.cs b/src/Navigator/Catalog/IBotActionCatalogBuilder.cs similarity index 86% rename from src/Navigator/Builder/IBotActionCatalogBuilder.cs rename to src/Navigator/Catalog/IBotActionCatalogBuilder.cs index 7c7a224..9573fc7 100644 --- a/src/Navigator/Builder/IBotActionCatalogBuilder.cs +++ b/src/Navigator/Catalog/IBotActionCatalogBuilder.cs @@ -1,13 +1,12 @@ -using Navigator.Actions; -using Navigator.Context; -using Telegram.Bot.Types; -using Telegram.Bot.Types.Enums; +using Navigator.Actions.Builder; -namespace Navigator.Builder; +namespace Navigator.Catalog; public interface IBotActionCatalogBuilder { public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler); + + public BotActionCatalog Build(); // public IBotActionBuilder OnUpdate(Func> condition, Delegate handler); // public IBotActionBuilder OnUpdate(Func> condition, Action handler); // public IBotActionBuilder OnUpdate(Func> condition, Func handler); diff --git a/src/Navigator/Builder/IBotActionCatalogBuilderExtensions.cs b/src/Navigator/Catalog/IBotActionCatalogBuilderExtensions.cs similarity index 63% rename from src/Navigator/Builder/IBotActionCatalogBuilderExtensions.cs rename to src/Navigator/Catalog/IBotActionCatalogBuilderExtensions.cs index 6dcbb0b..96dbc6b 100644 --- a/src/Navigator/Builder/IBotActionCatalogBuilderExtensions.cs +++ b/src/Navigator/Catalog/IBotActionCatalogBuilderExtensions.cs @@ -1,8 +1,9 @@ +using Navigator.Actions.Builder; using Navigator.Telegram; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; -namespace Navigator.Builder; +namespace Navigator.Catalog; public static class IBotActionCatalogBuilderExtensions { @@ -10,10 +11,6 @@ public static IBotActionBuilder OnCommand(this IBotActionCatalogBuilder builder, { var actionBuilder = builder.OnUpdate((Update update) => update.Message?.ExtractCommand() == command, handler); - var id = builder.Actions.FirstOrDefault(pair => pair.Value == actionBuilder.BotAction).Key; - - builder.ActionTypeByAction[id] = $"{typeof(MessageEntityType)}.{nameof(MessageEntityType.BotCommand)}"; - return actionBuilder; } } \ No newline at end of file From 3a6625fec2e43a18875e0acdbc1d37ca9bca54c6 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Fri, 9 Aug 2024 12:18:44 +0200 Subject: [PATCH 23/66] feat: create IBotActionBuilder --- .../Actions/Builder/IBotActionBuilder.cs | 9 +++ .../Builder/BotActionBuilderOptions.cs | 60 ------------------- src/Navigator/Builder/IBotActionBuilder.cs | 10 ---- 3 files changed, 9 insertions(+), 70 deletions(-) create mode 100644 src/Navigator/Actions/Builder/IBotActionBuilder.cs delete mode 100644 src/Navigator/Builder/BotActionBuilderOptions.cs delete mode 100644 src/Navigator/Builder/IBotActionBuilder.cs diff --git a/src/Navigator/Actions/Builder/IBotActionBuilder.cs b/src/Navigator/Actions/Builder/IBotActionBuilder.cs new file mode 100644 index 0000000..0a93384 --- /dev/null +++ b/src/Navigator/Actions/Builder/IBotActionBuilder.cs @@ -0,0 +1,9 @@ +namespace Navigator.Actions.Builder; + +public interface IBotActionBuilder +{ + public BotAction Build(); + public IBotActionBuilder WithPriority(ushort priority); + public IBotActionBuilder WithCooldown(TimeSpan cooldown); + public IBotActionBuilder SetType(string type); +} \ No newline at end of file diff --git a/src/Navigator/Builder/BotActionBuilderOptions.cs b/src/Navigator/Builder/BotActionBuilderOptions.cs deleted file mode 100644 index 3c74c07..0000000 --- a/src/Navigator/Builder/BotActionBuilderOptions.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace Navigator.Configuration; - -/// -public class BotActionBuilderOptions -{ - private readonly Dictionary _options; - - /// - /// Default constructor. - /// - public BotActionBuilderOptions() - { - _options = new Dictionary(); - } - - public bool TryRegisterOption(string key, object option) - { - return _options.TryAdd(key, option); - } - - public void ForceRegisterOption(string key, object option) - { - _options.Remove(key); - - TryRegisterOption(key, option); - } - - public TType? RetrieveOption(string key) - { - if (_options.TryGetValue(key, out var option)) - { - return (TType) option; - } - - return default; - } - - public Dictionary RetrieveAllOptions() - { - return _options; - } - - public void Import(Dictionary options, bool overwrite = false) - { - if (overwrite) - { - foreach (var (key, option) in options) - { - ForceRegisterOption(key, option); - } - - return; - } - - foreach (var (key, option) in options) - { - TryRegisterOption(key, option); - } - } -} \ No newline at end of file diff --git a/src/Navigator/Builder/IBotActionBuilder.cs b/src/Navigator/Builder/IBotActionBuilder.cs deleted file mode 100644 index 1335784..0000000 --- a/src/Navigator/Builder/IBotActionBuilder.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Navigator.Actions; -using Navigator.Configuration; - -namespace Navigator.Builder; - -public interface IBotActionBuilder -{ - public BotAction BotAction { get; } - public BotActionBuilderOptions Options { get; } -} \ No newline at end of file From 357cb983edc525ba531b47a90e143636535c3fde Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Fri, 9 Aug 2024 12:19:33 +0200 Subject: [PATCH 24/66] feat: implement BotActionBuilder & update BotAction --- src/Navigator/Actions/BotAction.cs | 16 +++--- src/Navigator/Actions/BotActionInformation.cs | 10 ++++ .../Actions/Builder/BotActionBuilder.cs | 55 +++++++++++++++++++ src/Navigator/Builder/BotActionBuilder.cs | 19 ------- 4 files changed, 72 insertions(+), 28 deletions(-) create mode 100644 src/Navigator/Actions/BotActionInformation.cs create mode 100644 src/Navigator/Actions/Builder/BotActionBuilder.cs delete mode 100644 src/Navigator/Builder/BotActionBuilder.cs diff --git a/src/Navigator/Actions/BotAction.cs b/src/Navigator/Actions/BotAction.cs index f67340f..7c58c4c 100644 --- a/src/Navigator/Actions/BotAction.cs +++ b/src/Navigator/Actions/BotAction.cs @@ -5,17 +5,15 @@ namespace Navigator.Actions; public record BotAction { - // private Func>? ConditionAsync { get; } = default; - // private Func? Condition { get; } = default; - // - // private Func? HandlerAsync { get; } = default; - // private Action? Handler { get; } = default; - - private static Delegate Condition { get; set; } - private static Delegate Handler { get; set; } + public readonly Guid Id; + public readonly BotActionInformation Information; + private static Delegate Condition; + private static Delegate Handler; - public BotAction(Delegate condition, Delegate handler) + public BotAction(Guid id, BotActionInformation information, Delegate condition, Delegate handler) { + Id = id; + Information = information; Condition = condition; Handler = handler; } diff --git a/src/Navigator/Actions/BotActionInformation.cs b/src/Navigator/Actions/BotActionInformation.cs new file mode 100644 index 0000000..31b255f --- /dev/null +++ b/src/Navigator/Actions/BotActionInformation.cs @@ -0,0 +1,10 @@ +namespace Navigator.Actions; + +public record BotActionInformation +{ + public required string ActionType; + public required Type[] ConditiionInputTypes; + public required Type[] HandlerInputTypes; + public required ushort Priority; + public required TimeSpan? Cooldown; +} \ No newline at end of file diff --git a/src/Navigator/Actions/Builder/BotActionBuilder.cs b/src/Navigator/Actions/Builder/BotActionBuilder.cs new file mode 100644 index 0000000..a087e39 --- /dev/null +++ b/src/Navigator/Actions/Builder/BotActionBuilder.cs @@ -0,0 +1,55 @@ +namespace Navigator.Actions.Builder; + +public class BotActionBuilder : IBotActionBuilder +{ + private readonly Guid _id; + private readonly Delegate _condition; + private readonly Delegate _handler; + private readonly Type[] _conditionInputTypes; + private readonly Type[] _handlerInputTypes; + private string _actionType { get; set; } + private ushort _priority { get; set; } + private TimeSpan? _cooldown { get; set; } + + public BotAction Build() + { + var information = new BotActionInformation + { + ActionType = _actionType, + ConditiionInputTypes = _conditionInputTypes, + HandlerInputTypes = _handlerInputTypes, + Priority = _priority, + Cooldown = _cooldown + }; + + return new BotAction(_id, information, _condition, _handler); + } + + public BotActionBuilder(Delegate condition, Delegate handler) + { + _id = Guid.NewGuid(); + _condition = condition; + _conditionInputTypes = condition.Method.GetParameters().Select(info => info.ParameterType).ToArray(); + _handler = handler; + _handlerInputTypes = handler.Method.GetParameters().Select(info => info.ParameterType).ToArray(); + _priority = Priority.Default; + } + + public IBotActionBuilder WithPriority(ushort priority) + { + _priority = priority; + return this; + } + + public IBotActionBuilder WithCooldown(TimeSpan cooldown) + { + _cooldown = cooldown; + return this; + } + + public IBotActionBuilder SetType(string type) + { + _actionType = type; + return this; + } +} \ No newline at end of file diff --git a/src/Navigator/Builder/BotActionBuilder.cs b/src/Navigator/Builder/BotActionBuilder.cs deleted file mode 100644 index dee451d..0000000 --- a/src/Navigator/Builder/BotActionBuilder.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Navigator.Actions; -using Navigator.Configuration; -using Navigator.Context; -using Telegram.Bot.Types; - -namespace Navigator.Builder; - -public class BotActionBuilder : IBotActionBuilder -{ - public BotAction BotAction { get; set; } - - public BotActionBuilderOptions Options { get; } - - public BotActionBuilder(BotAction botAction) - { - BotAction = botAction; - Options = new BotActionBuilderOptions(); - } -} \ No newline at end of file From e867582820e0c6715a839a67c373cb8efc678a6c Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Fri, 9 Aug 2024 12:20:00 +0200 Subject: [PATCH 25/66] feat: implement BotActionCatalogBuilder --- .../Builder/BotActionCatalogBuilder.cs | 22 -------------- .../Catalog/BotActionCatalogBuilder.cs | 29 +++++++++++++++++++ 2 files changed, 29 insertions(+), 22 deletions(-) delete mode 100644 src/Navigator/Builder/BotActionCatalogBuilder.cs create mode 100644 src/Navigator/Catalog/BotActionCatalogBuilder.cs diff --git a/src/Navigator/Builder/BotActionCatalogBuilder.cs b/src/Navigator/Builder/BotActionCatalogBuilder.cs deleted file mode 100644 index 28cd8b1..0000000 --- a/src/Navigator/Builder/BotActionCatalogBuilder.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Navigator.Actions; -using Navigator.Configuration; -using Navigator.Context; -using Telegram.Bot.Types; -using Telegram.Bot.Types.Enums; - -namespace Navigator.Builder; - -public class BotActionCatalogBuilder : IBotActionCatalogBuilder -{ - public Dictionary Actions { get; } = []; - - public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler) - { - var id = Guid.NewGuid(); - var actionBuilder = new BotActionBuilder(new BotAction(condition, handler)); - - Actions.Add(id, actionBuilder); - - return actionBuilder; - } -} \ No newline at end of file diff --git a/src/Navigator/Catalog/BotActionCatalogBuilder.cs b/src/Navigator/Catalog/BotActionCatalogBuilder.cs new file mode 100644 index 0000000..ecba739 --- /dev/null +++ b/src/Navigator/Catalog/BotActionCatalogBuilder.cs @@ -0,0 +1,29 @@ +using System.Collections.ObjectModel; +using Navigator.Actions; +using Navigator.Actions.Builder; + +namespace Navigator.Catalog; + +public class BotActionCatalogBuilder : IBotActionCatalogBuilder +{ + public List Actions { get; } = []; + + public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler) + { + var id = Guid.NewGuid(); + var actionBuilder = new BotActionBuilder(condition, handler); + + Actions.Add(actionBuilder); + + return actionBuilder; + } + + public BotActionCatalog Build() + { + var actions = Actions + .Select(actionBuilder => actionBuilder.Build()) + .ToList(); + + return new BotActionCatalog(actions); + } +} \ No newline at end of file From 4c300960f45f769f3bca533324456a2e5ae5e8d2 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Fri, 9 Aug 2024 12:21:36 +0200 Subject: [PATCH 26/66] feat: implement BotActionCatalog --- src/Navigator/Catalog/BotActionCatalog.cs | 30 +++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/Navigator/Catalog/BotActionCatalog.cs diff --git a/src/Navigator/Catalog/BotActionCatalog.cs b/src/Navigator/Catalog/BotActionCatalog.cs new file mode 100644 index 0000000..82dd11b --- /dev/null +++ b/src/Navigator/Catalog/BotActionCatalog.cs @@ -0,0 +1,30 @@ +using Navigator.Actions; + +namespace Navigator.Catalog; + +public record BotActionCatalog +{ + protected readonly Dictionary Actions; + protected readonly Dictionary PriorityByAction; + protected readonly Dictionary ActionsByType; + + public BotActionCatalog(IList actions) + { + Actions = actions.ToDictionary(action => action.Id); + PriorityByAction = actions.ToDictionary(action => action.Id, action => action.Information.Priority); + ActionsByType = actions.GroupBy(action => action.Information.ActionType) + .ToDictionary(grouping => grouping.Key, grouping => grouping.Select(action => action.Id).ToArray()); + } + + public IEnumerable Retrieve(string type, bool multiple = false) + { + if (ActionsByType.TryGetValue(type, out var filtered) is false) + { + return []; + } + + var actions = filtered.Select(id => Actions[id]).OrderBy(action => PriorityByAction[action.Id]); + + return multiple is false ? actions.Take(1) : actions; + } +} \ No newline at end of file From 6bc5732c06758bbaa2bd442912e0ffa96bcec3a0 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Fri, 9 Aug 2024 12:22:02 +0200 Subject: [PATCH 27/66] refactor: update using references --- src/Navigator/Configuration/ApplicationBuilderExtensions.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Navigator/Configuration/ApplicationBuilderExtensions.cs b/src/Navigator/Configuration/ApplicationBuilderExtensions.cs index bbb02ab..cdb0bc7 100644 --- a/src/Navigator/Configuration/ApplicationBuilderExtensions.cs +++ b/src/Navigator/Configuration/ApplicationBuilderExtensions.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Builder; -using Navigator.Builder; -using Action = Navigator.Actions.Action; +using Navigator.Catalog; namespace Navigator.Configuration; From fe7a8754d07fde2364722fcb26f5c5103a35ca38 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Fri, 9 Aug 2024 12:46:41 +0200 Subject: [PATCH 28/66] refactor: rename BotActionCatalogBuilder to BotActionCatalogFactory --- ...{BotActionCatalogBuilder.cs => BotActionCatalogFactory.cs} | 2 +- src/Navigator/Catalog/IBotActionCatalogBuilderExtensions.cs | 4 ++-- ...BotActionCatalogBuilder.cs => IBotActionCatalogFactory.cs} | 2 +- src/Navigator/Configuration/ApplicationBuilderExtensions.cs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) rename src/Navigator/Catalog/{BotActionCatalogBuilder.cs => BotActionCatalogFactory.cs} (91%) rename src/Navigator/Catalog/{IBotActionCatalogBuilder.cs => IBotActionCatalogFactory.cs} (95%) diff --git a/src/Navigator/Catalog/BotActionCatalogBuilder.cs b/src/Navigator/Catalog/BotActionCatalogFactory.cs similarity index 91% rename from src/Navigator/Catalog/BotActionCatalogBuilder.cs rename to src/Navigator/Catalog/BotActionCatalogFactory.cs index ecba739..c171f4f 100644 --- a/src/Navigator/Catalog/BotActionCatalogBuilder.cs +++ b/src/Navigator/Catalog/BotActionCatalogFactory.cs @@ -4,7 +4,7 @@ namespace Navigator.Catalog; -public class BotActionCatalogBuilder : IBotActionCatalogBuilder +public class BotActionCatalogFactory : IBotActionCatalogFactory { public List Actions { get; } = []; diff --git a/src/Navigator/Catalog/IBotActionCatalogBuilderExtensions.cs b/src/Navigator/Catalog/IBotActionCatalogBuilderExtensions.cs index 96dbc6b..c21af98 100644 --- a/src/Navigator/Catalog/IBotActionCatalogBuilderExtensions.cs +++ b/src/Navigator/Catalog/IBotActionCatalogBuilderExtensions.cs @@ -7,9 +7,9 @@ namespace Navigator.Catalog; public static class IBotActionCatalogBuilderExtensions { - public static IBotActionBuilder OnCommand(this IBotActionCatalogBuilder builder, string command, Delegate handler) + public static IBotActionBuilder OnCommand(this IBotActionCatalogFactory factory, string command, Delegate handler) { - var actionBuilder = builder.OnUpdate((Update update) => update.Message?.ExtractCommand() == command, handler); + var actionBuilder = factory.OnUpdate((Update update) => update.Message?.ExtractCommand() == command, handler); return actionBuilder; } diff --git a/src/Navigator/Catalog/IBotActionCatalogBuilder.cs b/src/Navigator/Catalog/IBotActionCatalogFactory.cs similarity index 95% rename from src/Navigator/Catalog/IBotActionCatalogBuilder.cs rename to src/Navigator/Catalog/IBotActionCatalogFactory.cs index 9573fc7..9266b21 100644 --- a/src/Navigator/Catalog/IBotActionCatalogBuilder.cs +++ b/src/Navigator/Catalog/IBotActionCatalogFactory.cs @@ -2,7 +2,7 @@ namespace Navigator.Catalog; -public interface IBotActionCatalogBuilder +public interface IBotActionCatalogFactory { public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler); diff --git a/src/Navigator/Configuration/ApplicationBuilderExtensions.cs b/src/Navigator/Configuration/ApplicationBuilderExtensions.cs index cdb0bc7..b6976b4 100644 --- a/src/Navigator/Configuration/ApplicationBuilderExtensions.cs +++ b/src/Navigator/Configuration/ApplicationBuilderExtensions.cs @@ -8,9 +8,9 @@ namespace Navigator.Configuration; /// public static class ApplicationBuilderExtensions { - public static IBotActionCatalogBuilder GetBot(this IApplicationBuilder builder) + public static IBotActionCatalogFactory GetBot(this IApplicationBuilder builder) { - return new BotActionCatalogBuilder(); + return new BotActionCatalogFactory(); } } \ No newline at end of file From b417ebb9df3a67165663c3a56e10799ef5ff0cd2 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Fri, 9 Aug 2024 16:51:18 +0200 Subject: [PATCH 29/66] feat: implement NavigatorStrategy Many changes to other implementations in order to fit NavigatorStrategy --- src/Navigator/Actions/BotAction.cs | 9 +- src/Navigator/Catalog/BotActionCatalog.cs | 5 +- .../Catalog/BotActionCatalogFactory.cs | 22 +++- .../Catalog/IBotActionCatalogFactory.cs | 2 +- src/Navigator/ServiceCollectionExtensions.cs | 3 + .../Strategy/Classifier/IUpdateClassifier.cs | 104 ++++++++++++++++++ src/Navigator/Strategy/INavigatorStrategy.cs | 8 ++ src/Navigator/Strategy/NavigatorStrategy.cs | 91 +++++++++++++++ 8 files changed, 234 insertions(+), 10 deletions(-) create mode 100644 src/Navigator/Strategy/Classifier/IUpdateClassifier.cs create mode 100644 src/Navigator/Strategy/INavigatorStrategy.cs create mode 100644 src/Navigator/Strategy/NavigatorStrategy.cs diff --git a/src/Navigator/Actions/BotAction.cs b/src/Navigator/Actions/BotAction.cs index 7c58c4c..9a7f67d 100644 --- a/src/Navigator/Actions/BotAction.cs +++ b/src/Navigator/Actions/BotAction.cs @@ -18,14 +18,17 @@ public BotAction(Guid id, BotActionInformation information, Delegate condition, Handler = handler; } - public async Task ExecuteCondition(params object[] args) + public async Task ExecuteCondition(params object[] args) { var result = Handler.DynamicInvoke(args); - if (result is Task task) + if (result is Task task) { - await task; + return await task; } + + //TODO: specify exception + throw new NavigatorException(); } public async Task ExecuteHandler(params object[] args) diff --git a/src/Navigator/Catalog/BotActionCatalog.cs b/src/Navigator/Catalog/BotActionCatalog.cs index 82dd11b..40f959c 100644 --- a/src/Navigator/Catalog/BotActionCatalog.cs +++ b/src/Navigator/Catalog/BotActionCatalog.cs @@ -16,7 +16,8 @@ public BotActionCatalog(IList actions) .ToDictionary(grouping => grouping.Key, grouping => grouping.Select(action => action.Id).ToArray()); } - public IEnumerable Retrieve(string type, bool multiple = false) + //TODO: rework this into IAsyncEnumerable and yield + public IEnumerable Retrieve(string type) { if (ActionsByType.TryGetValue(type, out var filtered) is false) { @@ -25,6 +26,6 @@ public IEnumerable Retrieve(string type, bool multiple = false) var actions = filtered.Select(id => Actions[id]).OrderBy(action => PriorityByAction[action.Id]); - return multiple is false ? actions.Take(1) : actions; + return actions; } } \ No newline at end of file diff --git a/src/Navigator/Catalog/BotActionCatalogFactory.cs b/src/Navigator/Catalog/BotActionCatalogFactory.cs index c171f4f..003d228 100644 --- a/src/Navigator/Catalog/BotActionCatalogFactory.cs +++ b/src/Navigator/Catalog/BotActionCatalogFactory.cs @@ -1,29 +1,43 @@ using System.Collections.ObjectModel; using Navigator.Actions; using Navigator.Actions.Builder; +using Telegram.Bot.Types.Enums; namespace Navigator.Catalog; public class BotActionCatalogFactory : IBotActionCatalogFactory { - public List Actions { get; } = []; + private List Actions { get; } = []; + private BotActionCatalog? Catalog { get; set; } public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler) { var id = Guid.NewGuid(); var actionBuilder = new BotActionBuilder(condition, handler); + actionBuilder.SetType($"{typeof(UpdateType)}.{nameof(UpdateType.Unknown)}"); + Actions.Add(actionBuilder); return actionBuilder; } - public BotActionCatalog Build() + public BotActionCatalog Retrieve() + { + if (Catalog is null) + { + Build(); + } + + return Catalog!; + } + + private void Build() { var actions = Actions .Select(actionBuilder => actionBuilder.Build()) .ToList(); - - return new BotActionCatalog(actions); + + Catalog = new BotActionCatalog(actions); } } \ No newline at end of file diff --git a/src/Navigator/Catalog/IBotActionCatalogFactory.cs b/src/Navigator/Catalog/IBotActionCatalogFactory.cs index 9266b21..8d9dfc3 100644 --- a/src/Navigator/Catalog/IBotActionCatalogFactory.cs +++ b/src/Navigator/Catalog/IBotActionCatalogFactory.cs @@ -6,7 +6,7 @@ public interface IBotActionCatalogFactory { public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler); - public BotActionCatalog Build(); + public BotActionCatalog Retrieve(); // public IBotActionBuilder OnUpdate(Func> condition, Delegate handler); // public IBotActionBuilder OnUpdate(Func> condition, Action handler); // public IBotActionBuilder OnUpdate(Func> condition, Func handler); diff --git a/src/Navigator/ServiceCollectionExtensions.cs b/src/Navigator/ServiceCollectionExtensions.cs index 5e91bf8..d5d50e7 100644 --- a/src/Navigator/ServiceCollectionExtensions.cs +++ b/src/Navigator/ServiceCollectionExtensions.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Navigator.Actions; using Navigator.Bundled.Extensions.Update; +using Navigator.Catalog; using Navigator.Client; using Navigator.Configuration; using Navigator.Context; @@ -42,6 +43,8 @@ public static NavigatorConfiguration AddNavigator(this IServiceCollection servic services.AddScoped(); + services.AddSingleton(); + services.AddScoped(); services.AddHostedService(); diff --git a/src/Navigator/Strategy/Classifier/IUpdateClassifier.cs b/src/Navigator/Strategy/Classifier/IUpdateClassifier.cs new file mode 100644 index 0000000..c6236e9 --- /dev/null +++ b/src/Navigator/Strategy/Classifier/IUpdateClassifier.cs @@ -0,0 +1,104 @@ +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; + +namespace Navigator.Strategy.Classifier; + +public interface IUpdateClassifier +{ + Task Process(Update update); +} + +public class UpdateClassifier : IUpdateClassifier +{ + public Task Process(Update update) + { + return Task.FromResult(update.Type switch + { + UpdateType.Unknown => $"{typeof(UpdateType)}.{nameof(UpdateType.Unknown)}", + UpdateType.Message when update.Message?.Entities?.First().Type == MessageEntityType.BotCommand + => $"{typeof(MessageType)}.{nameof(MessageEntityType.BotCommand)}", + UpdateType.Message => update.Message?.Type switch + { + MessageType.Unknown => $"{typeof(MessageType)}.{nameof(MessageType.Unknown)}", + MessageType.Text => $"{typeof(MessageType)}.{nameof(MessageType.Text)}", + MessageType.Photo => $"{typeof(MessageType)}.{nameof(MessageType.Photo)}", + MessageType.Audio => $"{typeof(MessageType)}.{nameof(MessageType.Audio)}", + MessageType.Video => $"{typeof(MessageType)}.{nameof(MessageType.Video)}", + MessageType.Voice => $"{typeof(MessageType)}.{nameof(MessageType.Voice)}", + MessageType.Document => $"{typeof(MessageType)}.{nameof(MessageType.Document)}", + MessageType.Sticker => $"{typeof(MessageType)}.{nameof(MessageType.Sticker)}", + MessageType.Location => $"{typeof(MessageType)}.{nameof(MessageType.Location)}", + MessageType.Contact => $"{typeof(MessageType)}.{nameof(MessageType.Contact)}", + MessageType.Venue => $"{typeof(MessageType)}.{nameof(MessageType.Venue)}", + MessageType.Game => $"{typeof(MessageType)}.{nameof(MessageType.Game)}", + MessageType.VideoNote => $"{typeof(MessageType)}.{nameof(MessageType.VideoNote)}", + MessageType.Invoice => $"{typeof(MessageType)}.{nameof(MessageType.Invoice)}", + MessageType.SuccessfulPayment => $"{typeof(MessageType)}.{nameof(MessageType.SuccessfulPayment)}", + MessageType.ConnectedWebsite => $"{typeof(MessageType)}.{nameof(MessageType.ConnectedWebsite)}", + MessageType.NewChatMembers => $"{typeof(MessageType)}.{nameof(MessageType.NewChatMembers)}", + MessageType.LeftChatMember => $"{typeof(MessageType)}.{nameof(MessageType.LeftChatMember)}", + MessageType.NewChatTitle => $"{typeof(MessageType)}.{nameof(MessageType.NewChatTitle)}", + MessageType.NewChatPhoto => $"{typeof(MessageType)}.{nameof(MessageType.NewChatPhoto)}", + MessageType.PinnedMessage => $"{typeof(MessageType)}.{nameof(MessageType.PinnedMessage)}", + MessageType.DeleteChatPhoto => $"{typeof(MessageType)}.{nameof(MessageType.DeleteChatPhoto)}", + MessageType.GroupChatCreated => $"{typeof(MessageType)}.{nameof(MessageType.GroupChatCreated)}", + MessageType.SupergroupChatCreated => $"{typeof(MessageType)}.{nameof(MessageType.SupergroupChatCreated)}", + MessageType.ChannelChatCreated => $"{typeof(MessageType)}.{nameof(MessageType.ChannelChatCreated)}", + MessageType.MigrateFromChatId => $"{typeof(MessageType)}.{nameof(MessageType.MigrateFromChatId)}", + MessageType.MigrateToChatId => $"{typeof(MessageType)}.{nameof(MessageType.MigrateToChatId)}", + MessageType.Poll => $"{typeof(MessageType)}.{nameof(MessageType.Poll)}", + MessageType.Dice => $"{typeof(MessageType)}.{nameof(MessageType.Dice)}", + MessageType.MessageAutoDeleteTimerChanged => $"{typeof(MessageType)}.{nameof(MessageType.MessageAutoDeleteTimerChanged)}", + MessageType.ProximityAlertTriggered => $"{typeof(MessageType)}.{nameof(MessageType.ProximityAlertTriggered)}", + MessageType.WebAppData => $"{typeof(MessageType)}.{nameof(MessageType.WebAppData)}", + MessageType.VideoChatScheduled => $"{typeof(MessageType)}.{nameof(MessageType.VideoChatScheduled)}", + MessageType.VideoChatStarted => $"{typeof(MessageType)}.{nameof(MessageType.VideoChatStarted)}", + MessageType.VideoChatEnded => $"{typeof(MessageType)}.{nameof(MessageType.VideoChatEnded)}", + MessageType.VideoChatParticipantsInvited => $"{typeof(MessageType)}.{nameof(MessageType.VideoChatParticipantsInvited)}", + MessageType.Animation => $"{typeof(MessageType)}.{nameof(MessageType.Animation)}", + MessageType.ForumTopicCreated => $"{typeof(MessageType)}.{nameof(MessageType.ForumTopicCreated)}", + MessageType.ForumTopicClosed => $"{typeof(MessageType)}.{nameof(MessageType.ForumTopicClosed)}", + MessageType.ForumTopicReopened => $"{typeof(MessageType)}.{nameof(MessageType.ForumTopicReopened)}", + MessageType.ForumTopicEdited => $"{typeof(MessageType)}.{nameof(MessageType.ForumTopicEdited)}", + MessageType.GeneralForumTopicHidden => $"{typeof(MessageType)}.{nameof(MessageType.GeneralForumTopicHidden)}", + MessageType.GeneralForumTopicUnhidden => $"{typeof(MessageType)}.{nameof(MessageType.GeneralForumTopicUnhidden)}", + MessageType.WriteAccessAllowed => $"{typeof(MessageType)}.{nameof(MessageType.WriteAccessAllowed)}", + MessageType.UsersShared => $"{typeof(MessageType)}.{nameof(MessageType.UsersShared)}", + MessageType.ChatShared => $"{typeof(MessageType)}.{nameof(MessageType.ChatShared)}", + MessageType.Story => $"{typeof(MessageType)}.{nameof(MessageType.Story)}", + MessageType.PassportData => $"{typeof(MessageType)}.{nameof(MessageType.PassportData)}", + MessageType.GiveawayCreated => $"{typeof(MessageType)}.{nameof(MessageType.GiveawayCreated)}", + MessageType.Giveaway => $"{typeof(MessageType)}.{nameof(MessageType.Giveaway)}", + MessageType.GiveawayWinners => $"{typeof(MessageType)}.{nameof(MessageType.GiveawayWinners)}", + MessageType.GiveawayCompleted => $"{typeof(MessageType)}.{nameof(MessageType.GiveawayCompleted)}", + MessageType.BoostAdded => $"{typeof(MessageType)}.{nameof(MessageType.BoostAdded)}", + MessageType.ChatBackgroundSet => $"{typeof(MessageType)}.{nameof(MessageType.ChatBackgroundSet)}", + MessageType.PaidMedia => $"{typeof(MessageType)}.{nameof(MessageType.PaidMedia)}", + MessageType.RefundedPayment => $"{typeof(MessageType)}.{nameof(MessageType.RefundedPayment)}", + _ => $"{typeof(MessageType)}.{nameof(MessageType.Unknown)}" + }, + UpdateType.InlineQuery => $"{typeof(UpdateType)}.{nameof(UpdateType.InlineQuery)}", + UpdateType.ChosenInlineResult => $"{typeof(UpdateType)}.{nameof(UpdateType.ChosenInlineResult)}", + UpdateType.CallbackQuery => $"{typeof(UpdateType)}.{nameof(UpdateType.CallbackQuery)}", + UpdateType.EditedMessage => $"{typeof(UpdateType)}.{nameof(UpdateType.EditedMessage)}", + UpdateType.ChannelPost => $"{typeof(UpdateType)}.{nameof(UpdateType.ChannelPost)}", + UpdateType.EditedChannelPost => $"{typeof(UpdateType)}.{nameof(UpdateType.EditedChannelPost)}", + UpdateType.ShippingQuery => $"{typeof(UpdateType)}.{nameof(UpdateType.ShippingQuery)}", + UpdateType.PreCheckoutQuery => $"{typeof(UpdateType)}.{nameof(UpdateType.PreCheckoutQuery)}", + UpdateType.Poll => $"{typeof(UpdateType)}.{nameof(UpdateType.Poll)}", + UpdateType.PollAnswer => $"{typeof(UpdateType)}.{nameof(UpdateType.PollAnswer)}", + UpdateType.MyChatMember => $"{typeof(UpdateType)}.{nameof(UpdateType.MyChatMember)}", + UpdateType.ChatMember => $"{typeof(UpdateType)}.{nameof(UpdateType.ChatMember)}", + UpdateType.ChatJoinRequest => $"{typeof(UpdateType)}.{nameof(UpdateType.ChatJoinRequest)}", + UpdateType.MessageReaction => $"{typeof(UpdateType)}.{nameof(UpdateType.MessageReaction)}", + UpdateType.MessageReactionCount => $"{typeof(UpdateType)}.{nameof(UpdateType.MessageReactionCount)}", + UpdateType.ChatBoost => $"{typeof(UpdateType)}.{nameof(UpdateType.ChatBoost)}", + UpdateType.RemovedChatBoost => $"{typeof(UpdateType)}.{nameof(UpdateType.RemovedChatBoost)}", + UpdateType.BusinessConnection => $"{typeof(UpdateType)}.{nameof(UpdateType.BusinessConnection)}", + UpdateType.BusinessMessage => $"{typeof(UpdateType)}.{nameof(UpdateType.BusinessMessage)}", + UpdateType.EditedBusinessMessage => $"{typeof(UpdateType)}.{nameof(UpdateType.EditedBusinessMessage)}", + UpdateType.DeletedBusinessMessages => $"{typeof(UpdateType)}.{nameof(UpdateType.DeletedBusinessMessages)}", + _ => $"{typeof(UpdateType)}.{nameof(UpdateType.Unknown)}" + }); + } +} \ No newline at end of file diff --git a/src/Navigator/Strategy/INavigatorStrategy.cs b/src/Navigator/Strategy/INavigatorStrategy.cs new file mode 100644 index 0000000..33e4ab6 --- /dev/null +++ b/src/Navigator/Strategy/INavigatorStrategy.cs @@ -0,0 +1,8 @@ +using Telegram.Bot.Types; + +namespace Navigator.Strategy; + +public interface INavigatorStrategy +{ + public Task Invoke(Update update); +} \ No newline at end of file diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs new file mode 100644 index 0000000..fc9e56e --- /dev/null +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -0,0 +1,91 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Navigator.Actions; +using Navigator.Bundled.Extensions.Update; +using Navigator.Catalog; +using Navigator.Context; +using Navigator.Context.Accessor; +using Navigator.Strategy.Classifier; +using Telegram.Bot.Types; + +namespace Navigator.Strategy; + +public class NavigatorStrategy : INavigatorStrategy +{ + private readonly ILogger _logger; + private readonly BotActionCatalog _catalog; + private readonly IUpdateClassifier _classifier; + private readonly IServiceProvider _serviceProvider; + private readonly INavigatorContextAccessor _contextAccessor; + + public NavigatorStrategy(ILogger logger, IBotActionCatalogFactory catalogFactory, IUpdateClassifier classifier, + IServiceProvider serviceProvider, INavigatorContextAccessor contextAccessor) + { + _logger = logger; + _catalog = catalogFactory.Retrieve(); + _classifier = classifier; + _serviceProvider = serviceProvider; + _contextAccessor = contextAccessor; + } + + public async Task Invoke(Update update) + { + var actionType = await _classifier.Process(update); + + var relevantActions = _catalog.Retrieve(actionType); + + foreach (var action in await FilterActionsThatCanHandleUpdate(relevantActions)) + { + await ExecuteAction(action); + } + } + + //TODO: rework this into IAsyncEnumerable and yield + private async Task> FilterActionsThatCanHandleUpdate(IEnumerable actions) + { + var successActions = new List(); + + foreach (var action in actions) + { + var arguments = new List(); + + foreach (var inputType in action.Information.ConditiionInputTypes) + { + arguments.Add(inputType switch + { + not null when inputType == typeof(INavigatorContext) => _contextAccessor.NavigatorContext, + not null when inputType == typeof(Update) => _contextAccessor.NavigatorContext.GetUpdate(), + not null => _serviceProvider.GetRequiredService(inputType), + //TODO: this exception should never happen. + _ => throw new NavigatorException() + }); + } + + if (await action.ExecuteCondition(arguments)) + { + successActions.Add(action); + } + } + + return successActions; + } + + private async Task ExecuteAction(BotAction action) + { + var arguments = new List(); + + foreach (var inputType in action.Information.HandlerInputTypes) + { + arguments.Add(inputType switch + { + not null when inputType == typeof(INavigatorContext) => _contextAccessor.NavigatorContext, + not null when inputType == typeof(Update) => _contextAccessor.NavigatorContext.GetUpdate(), + not null => _serviceProvider.GetRequiredService(inputType), + //TODO: this exception should never happen. + _ => throw new NavigatorException() + }); + } + + await action.ExecuteHandler(arguments); + } +} \ No newline at end of file From a02c0f79d18de23852dbaab649e0a9d31b2c10dd Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Mon, 19 Aug 2024 13:16:50 +0200 Subject: [PATCH 30/66] feat: get ride of old stuff, bring some new stuff --- src/Navigator/Actions/Action.cs | 35 ----- src/Navigator/Actions/ActionLauncher.cs | 90 ------------ .../Attributes/ActionPriorityAttribute.cs | 22 --- .../Actions/Attributes/ActionTypeAttribute.cs | 22 --- src/Navigator/Actions/IActionLauncher.cs | 13 -- .../Actions/NavigatorOptionsExtensions.cs | 135 ------------------ src/Navigator/Actions/Status.cs | 28 ---- .../Bundled/Actions/CommandAction.cs | 32 ----- .../Actions/Messages/AnimationAction.cs | 24 ---- .../Bundled/Actions/Messages/AudioAction.cs | 23 --- .../Actions/Messages/ChatMemberLeftAction.cs | 23 --- .../Messages/ChatMembersAddedAction.cs | 23 --- .../Messages/ChatPhotoChangedAction.cs | 23 --- .../Messages/ChatPhotoDeletedAction.cs | 16 --- .../Actions/Messages/ChatSharedAction.cs | 24 ---- .../Messages/ChatTitleChangedAction.cs | 22 --- .../Bundled/Actions/Messages/ContactAction.cs | 24 ---- .../Bundled/Actions/Messages/DiceAction.cs | 23 --- .../Messages/ForumTopicClosedAction.cs | 23 --- .../Messages/ForumTopicCreatedAction.cs | 24 ---- .../Messages/ForumTopicEditedAction.cs | 23 --- .../Messages/ForumTopicReopenedAction.cs | 23 --- .../Bundled/Actions/Messages/GameAction.cs | 23 --- .../Messages/GeneralForumTopicHiddenAction.cs | 23 --- .../GeneralForumTopicUnhiddenAction.cs | 23 --- .../Actions/Messages/GroupCreatedAction.cs | 23 --- .../Bundled/Actions/Messages/InvoiceAction.cs | 23 --- .../Actions/Messages/LocationAction.cs | 24 ---- .../Bundled/Actions/Messages/MessageAction.cs | 51 ------- .../MessageAutoDeleteTimerChangedAction.cs | 23 --- .../Actions/Messages/MessagePinnedAction.cs | 23 --- .../Messages/MigratedFromGroupAction.cs | 29 ---- .../Messages/MigratedToSupergroupAction.cs | 30 ---- .../Bundled/Actions/Messages/PhotoAction.cs | 24 ---- .../Actions/Messages/PollMessageAction.cs | 23 --- .../Messages/ProximityAlertTriggeredAction.cs | 23 --- .../Bundled/Actions/Messages/StickerAction.cs | 23 --- .../Messages/SuccessfulPaymentAction.cs | 24 ---- .../Bundled/Actions/Messages/TextAction.cs | 23 --- .../Bundled/Actions/Messages/VenueAction.cs | 23 --- .../Bundled/Actions/Messages/VideoAction.cs | 23 --- .../Actions/Messages/VideoChatEndedAction.cs | 23 --- .../VideoChatParticipantsInvitedAction.cs | 24 ---- .../Messages/VideoChatScheduledAction.cs | 23 --- .../Messages/VideoChatStartedAction.cs | 23 --- .../Actions/Messages/VideoNoteAction.cs | 23 --- .../Bundled/Actions/Messages/VoiceAction.cs | 23 --- .../Actions/Messages/WebAppDataAction.cs | 23 --- .../Messages/WebsiteConnectedAction.cs | 22 --- .../Messages/WriteAccessAllowedAction.cs | 23 --- .../Bundled/Actions/UnknownAction.cs | 18 --- .../Actions/Updates/CallbackQueryAction.cs | 45 ------ .../Actions/Updates/ChannelCreatedAction.cs | 18 --- .../Actions/Updates/ChannelPostAction.cs | 27 ---- .../Actions/Updates/ChatJoinRequestAction.cs | 27 ---- .../Actions/Updates/ChatMemberAction.cs | 27 ---- .../Updates/ChosenInlineResultAction.cs | 39 ----- .../Bundled/Actions/Updates/DocumentAction.cs | 27 ---- .../Updates/EditedChannelPostAction.cs | 26 ---- .../Actions/Updates/EditedMessageAction.cs | 36 ----- .../Actions/Updates/InlineQueryAction.cs | 39 ----- .../Actions/Updates/MyChatMemberAction.cs | 28 ---- .../Actions/Updates/PollAnswerAction.cs | 27 ---- .../Actions/Updates/PollUpdateAction.cs | 27 ---- .../Actions/Updates/PreCheckoutQueryAction.cs | 18 --- .../Actions/Updates/ShippingQueryAction.cs | 18 --- .../Updates/SupergroupCreatedAction.cs | 19 --- ...avigatorContextBuilderOptionsExtensions.cs | 24 ---- ...avigatorContextBuilderOptionsExtensions.cs | 19 --- .../Update/NavigatorContextExtensions.cs | 40 ------ .../Update/UpdateNavigatorContextExtension.cs | 17 --- ...sions.cs => BotActionCatalogExtensions.cs} | 3 +- .../{ => Factory}/BotActionCatalogFactory.cs | 0 .../{ => Factory}/IBotActionCatalogFactory.cs | 0 .../EndpointRouteBuilderExtensions.cs | 5 +- .../NavigatorRouteConfiguration.cs | 46 +++--- .../{ => Options}/INavigatorOptions.cs | 0 .../{ => Options}/NavigatorOptions.cs | 0 .../NavigatorOptionsCollectionExtensions.cs | 0 .../Accessor/INavigatorContextAccessor.cs | 12 -- .../Accessor/NavigatorContextAccessor.cs | 13 -- .../Builder/INavigatorContextBuilder.cs | 16 --- .../Builder/NavigatorContextBuilder.cs | 45 ------ .../INavigatorContextBuilderOptions.cs | 36 ----- .../Options/NavigatorContextBuilderOptions.cs | 46 ------ src/Navigator/Context/INavigatorContext.cs | 40 ------ .../Context/INavigatorContextFactory.cs | 22 --- src/Navigator/Context/NavigatorContext.cs | 25 ---- .../Context/NavigatorContextFactory.cs | 38 ----- src/Navigator/Entities/Bot.cs | 11 -- .../Extensions/INavigatorContextExtension.cs | 18 --- src/Navigator/NavigatorException.cs | 5 - src/Navigator/ServiceCollectionExtensions.cs | 2 - src/Navigator/Strategy/NavigatorStrategy.cs | 39 ++--- src/Navigator/TelegramMiddleware.cs | 130 ----------------- src/Sample/Program.cs | 10 ++ 96 files changed, 58 insertions(+), 2453 deletions(-) delete mode 100644 src/Navigator/Actions/Action.cs delete mode 100644 src/Navigator/Actions/ActionLauncher.cs delete mode 100644 src/Navigator/Actions/Attributes/ActionPriorityAttribute.cs delete mode 100644 src/Navigator/Actions/Attributes/ActionTypeAttribute.cs delete mode 100644 src/Navigator/Actions/IActionLauncher.cs delete mode 100644 src/Navigator/Actions/NavigatorOptionsExtensions.cs delete mode 100644 src/Navigator/Actions/Status.cs delete mode 100644 src/Navigator/Bundled/Actions/CommandAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/AnimationAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/AudioAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/ChatMemberLeftAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/ChatMembersAddedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/ChatPhotoChangedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/ChatPhotoDeletedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/ChatSharedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/ChatTitleChangedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/ContactAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/DiceAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/ForumTopicClosedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/ForumTopicCreatedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/ForumTopicEditedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/ForumTopicReopenedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/GameAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/GeneralForumTopicHiddenAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/GeneralForumTopicUnhiddenAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/GroupCreatedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/InvoiceAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/LocationAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/MessageAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/MessageAutoDeleteTimerChangedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/MessagePinnedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/MigratedFromGroupAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/MigratedToSupergroupAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/PhotoAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/PollMessageAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/ProximityAlertTriggeredAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/StickerAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/SuccessfulPaymentAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/TextAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/VenueAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/VideoAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/VideoChatEndedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/VideoChatParticipantsInvitedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/VideoChatScheduledAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/VideoChatStartedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/VideoNoteAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/VoiceAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/WebAppDataAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/WebsiteConnectedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Messages/WriteAccessAllowedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/UnknownAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/CallbackQueryAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/ChannelCreatedAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/ChannelPostAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/ChatJoinRequestAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/ChatMemberAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/ChosenInlineResultAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/DocumentAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/EditedChannelPostAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/EditedMessageAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/InlineQueryAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/MyChatMemberAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/PollAnswerAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/PollUpdateAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/PreCheckoutQueryAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/ShippingQueryAction.cs delete mode 100644 src/Navigator/Bundled/Actions/Updates/SupergroupCreatedAction.cs delete mode 100644 src/Navigator/Bundled/Extensions/ActionType/NavigatorContextBuilderOptionsExtensions.cs delete mode 100644 src/Navigator/Bundled/Extensions/Update/NavigatorContextBuilderOptionsExtensions.cs delete mode 100644 src/Navigator/Bundled/Extensions/Update/NavigatorContextExtensions.cs delete mode 100644 src/Navigator/Bundled/Extensions/Update/UpdateNavigatorContextExtension.cs rename src/Navigator/Catalog/{IBotActionCatalogBuilderExtensions.cs => BotActionCatalogExtensions.cs} (82%) rename src/Navigator/Catalog/{ => Factory}/BotActionCatalogFactory.cs (100%) rename src/Navigator/Catalog/{ => Factory}/IBotActionCatalogFactory.cs (100%) rename src/Navigator/Configuration/{ => Options}/INavigatorOptions.cs (100%) rename src/Navigator/Configuration/{ => Options}/NavigatorOptions.cs (100%) rename src/Navigator/Configuration/{ => Options}/NavigatorOptionsCollectionExtensions.cs (100%) delete mode 100644 src/Navigator/Context/Accessor/INavigatorContextAccessor.cs delete mode 100644 src/Navigator/Context/Accessor/NavigatorContextAccessor.cs delete mode 100644 src/Navigator/Context/Builder/INavigatorContextBuilder.cs delete mode 100644 src/Navigator/Context/Builder/NavigatorContextBuilder.cs delete mode 100644 src/Navigator/Context/Builder/Options/INavigatorContextBuilderOptions.cs delete mode 100644 src/Navigator/Context/Builder/Options/NavigatorContextBuilderOptions.cs delete mode 100644 src/Navigator/Context/INavigatorContext.cs delete mode 100644 src/Navigator/Context/INavigatorContextFactory.cs delete mode 100644 src/Navigator/Context/NavigatorContext.cs delete mode 100644 src/Navigator/Context/NavigatorContextFactory.cs delete mode 100644 src/Navigator/Extensions/INavigatorContextExtension.cs delete mode 100644 src/Navigator/TelegramMiddleware.cs diff --git a/src/Navigator/Actions/Action.cs b/src/Navigator/Actions/Action.cs deleted file mode 100644 index 60ae0a6..0000000 --- a/src/Navigator/Actions/Action.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context; -using Navigator.Context.Accessor; - -namespace Navigator.Actions; - -[ActionPriority(Actions.Priority.Default)] -public abstract record Action -{ - private readonly INavigatorContextAccessor _navigatorContextAccessor; - - protected INavigatorContext Context => _navigatorContextAccessor.NavigatorContext; - - public readonly DateTime Timestamp; - - protected Action(INavigatorContextAccessor navigatorContextAccessor) - { - _navigatorContextAccessor = navigatorContextAccessor; - Timestamp = DateTime.UtcNow; - } - - public abstract bool CanHandleCurrentContext(CancellationToken cancellationToken = default); - - public abstract Task Handle(CancellationToken cancellationToken = default); - - protected static Status Success() - { - return new Status(true); - } - - protected static Status Error() - { - return new Status(false); - } -} \ No newline at end of file diff --git a/src/Navigator/Actions/ActionLauncher.cs b/src/Navigator/Actions/ActionLauncher.cs deleted file mode 100644 index d96360f..0000000 --- a/src/Navigator/Actions/ActionLauncher.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System.Collections.Immutable; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Navigator.Configuration; -using Navigator.Context.Accessor; -using Telegram.Bot; -using Telegram.Bot.Types.Enums; - -namespace Navigator.Actions; - -internal class ActionLauncher : IActionLauncher -{ - private readonly ILogger _logger; - private readonly INavigatorContextAccessor _navigatorContextAccessor; - private readonly IServiceProvider _serviceProvider; - private readonly NavigatorOptions _navigatorOptions; - private readonly ImmutableDictionary _actions; - private readonly ImmutableDictionary _priorities; - - public ActionLauncher(ILogger logger, NavigatorOptions navigatorOptions, - INavigatorContextAccessor navigatorContextAccessor, IServiceProvider serviceProvider) - { - _logger = logger; - _navigatorContextAccessor = navigatorContextAccessor; - _serviceProvider = serviceProvider; - _navigatorOptions = navigatorOptions; - _actions = _navigatorOptions.RetrieveActions(); - _priorities = _navigatorOptions.RetrievePriorities(); - } - - public async Task Launch() - { - var actions = GetActions(); - var chatId = _navigatorContextAccessor.NavigatorContext.Conversation.Chat!.Id; - - foreach (var action in actions) - { - try - { - if (_navigatorOptions.TypingNotificationIsEnabled()) - { - await _navigatorContextAccessor.NavigatorContext.Client.SendChatActionAsync(chatId, ChatAction.Typing); - } - - // TODO: propagate cancellation token - await action.Handle(CancellationToken.None); - } - catch (Exception e) - { - _logger.LogError(e, "Unhandled exception running {ActionName} ({@ActionData})", action.GetType().Name, action); - } - } - } - - private IEnumerable GetActions() - { - if (string.IsNullOrWhiteSpace(_navigatorContextAccessor.NavigatorContext.ActionType)) - { - return Array.Empty(); - } - - var actions = _actions - // .Where(a => - // a.Key == _navigatorContextAccessor.NavigatorContext.ActionType || - // a.Key == nameof(ProviderAgnosticAction)) - .ToImmutableList(); - - if (_navigatorOptions.MultipleActionsUsageIsEnabled()) - { - return actions - .SelectMany(groups => groups.Value) - .SelectMany(actionType => _serviceProvider.GetServices(actionType) - .Select(action => ((Action)action!, actionType.FullName))) - .Where(a => a.Item1.CanHandleCurrentContext()) - .OrderBy(a => _priorities.GetValueOrDefault(a.FullName ?? string.Empty, Priority.Default)) - .Select(a => a.Item1) - .AsEnumerable(); - } - - var action = actions - .SelectMany(groups => groups.Value) - .SelectMany(actionType => _serviceProvider.GetServices(actionType) - .Select(action => ((Action)action!, actionType.FullName))) - .OrderBy(a => _priorities.GetValueOrDefault(a.FullName ?? string.Empty, Priority.Default)) - .Select(a => a.Item1) - .FirstOrDefault(a => a.CanHandleCurrentContext()); - - return action is not null ? new[] { action } : []; - } -} \ No newline at end of file diff --git a/src/Navigator/Actions/Attributes/ActionPriorityAttribute.cs b/src/Navigator/Actions/Attributes/ActionPriorityAttribute.cs deleted file mode 100644 index 4254103..0000000 --- a/src/Navigator/Actions/Attributes/ActionPriorityAttribute.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Navigator.Actions.Attributes; - -/// -/// Sets the priority of an action when multiple actions are available for the same trigger. -/// -[System.AttributeUsage(System.AttributeTargets.Class)] -public class ActionPriorityAttribute : System.Attribute -{ - /// - /// Priority. - /// - public readonly ushort Priority; - - /// - /// Sets the action priority. - /// - /// - public ActionPriorityAttribute(ushort priority) - { - Priority = priority; - } -} \ No newline at end of file diff --git a/src/Navigator/Actions/Attributes/ActionTypeAttribute.cs b/src/Navigator/Actions/Attributes/ActionTypeAttribute.cs deleted file mode 100644 index eced23b..0000000 --- a/src/Navigator/Actions/Attributes/ActionTypeAttribute.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Navigator.Actions.Attributes; - -/// -/// Attribute for setting the action type. -/// -[System.AttributeUsage(System.AttributeTargets.Class)] -public class ActionTypeAttribute : System.Attribute -{ - /// - /// Action type. - /// - public readonly string ActionType; - - /// - /// Sets the action type. - /// - /// - public ActionTypeAttribute(string action) - { - ActionType = action; - } -} \ No newline at end of file diff --git a/src/Navigator/Actions/IActionLauncher.cs b/src/Navigator/Actions/IActionLauncher.cs deleted file mode 100644 index ac122b5..0000000 --- a/src/Navigator/Actions/IActionLauncher.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Navigator.Actions; - -/// -/// Action launcher interface. -/// -public interface IActionLauncher -{ - /// - /// Launches one or more actions. - /// - /// - Task Launch(); -} \ No newline at end of file diff --git a/src/Navigator/Actions/NavigatorOptionsExtensions.cs b/src/Navigator/Actions/NavigatorOptionsExtensions.cs deleted file mode 100644 index 859ef05..0000000 --- a/src/Navigator/Actions/NavigatorOptionsExtensions.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System.Collections.Immutable; -using Navigator.Actions.Attributes; -using Navigator.Configuration; - -namespace Navigator.Actions; - -/// -/// Extensions for . -/// -public static class NavigatorOptionsExtensions -{ - #region NavigatorActionTypeCollection - - private const string NavigatorActionTypeCollection = "_navigator.options.action_type_collection"; - - /// - /// Pseudo-internal call, don't use it unless you know what you are doing. - /// - /// - /// - /// - public static void RegisterActionsCore(this NavigatorOptions navigatorOptions, IEnumerable actions, bool force = false) - { - var actionsDictionary = actions.GroupBy(type => type.GetActionType()) - .ToImmutableDictionary(types => types.Key, types => types.ToArray()); - - if (force) - { - navigatorOptions.ForceRegisterOption(NavigatorActionTypeCollection, actionsDictionary); - } - else - { - navigatorOptions.TryRegisterOption(NavigatorActionTypeCollection, actionsDictionary); - } - } - - /// - /// Pseudo-internal call, don't use it unless you know what you are doing. - /// - /// - /// - public static ImmutableDictionary RetrieveActions(this NavigatorOptions navigatorOptions) - { - return navigatorOptions.RetrieveOption>(NavigatorActionTypeCollection) ?? ImmutableDictionary.Empty; - } - - #endregion - - #region NavigatorActionPriorityCollection - - private const string NavigatorActionPriorityCollection = "_navigator.options.action_priority_collection"; - - /// - /// Pseudo-internal call, don't use it unless you know what you are doing. - /// - /// - /// - /// - /// - public static void RegisterActionsPriorityCore(this NavigatorOptions navigatorOptions, IEnumerable actions, bool force = false) - { - var priorityTable = actions.ToImmutableDictionary( - type => type.FullName ?? string.Empty, - type => type.GetActionPriority()); - - if (force) - { - navigatorOptions.ForceRegisterOption(NavigatorActionPriorityCollection, priorityTable); - - } - else - { - navigatorOptions.TryRegisterOption(NavigatorActionPriorityCollection, priorityTable); - } - } - - /// - /// Pseudo-internal call, don't use it unless you know what you are doing. - /// - /// - /// - public static ImmutableDictionary RetrievePriorities(this NavigatorOptions navigatorOptions) - { - return navigatorOptions.RetrieveOption>(NavigatorActionPriorityCollection) ?? ImmutableDictionary.Empty; - } - - #endregion - - internal static string GetActionType(this Type? type) - { - ActionTypeAttribute? actionTypeAttribute = default; - - if (type?.CustomAttributes.Any(data => data.AttributeType == typeof(ActionTypeAttribute)) ?? false) - { - actionTypeAttribute = Attribute.GetCustomAttribute(type, typeof(ActionTypeAttribute)) as ActionTypeAttribute; - - return actionTypeAttribute?.ActionType ?? string.Empty; - } - - if (type?.BaseType is not null && !type.BaseType.IsInterface) - { - var action = GetActionType(type.BaseType); - - if (action != string.Empty) - { - return action; - } - } - - if (type is not null) - { - actionTypeAttribute = Attribute.GetCustomAttribute(type, typeof(ActionTypeAttribute)) as ActionTypeAttribute; - } - - return actionTypeAttribute?.ActionType ?? string.Empty; - } - internal static ushort GetActionPriority(this Type? type) - { - if (type?.CustomAttributes.Any(data => data.AttributeType == typeof(ActionPriorityAttribute)) ?? false) - { - var priorityAttribute = (ActionPriorityAttribute) Attribute.GetCustomAttribute(type, typeof(ActionPriorityAttribute))!; - - return priorityAttribute.Priority; - } - - if (type?.BaseType is not null && !type.BaseType.IsInterface) - { - var priority = GetActionPriority(type.BaseType); - - return priority; - } - - return Priority.Default; - } -} \ No newline at end of file diff --git a/src/Navigator/Actions/Status.cs b/src/Navigator/Actions/Status.cs deleted file mode 100644 index 51d9342..0000000 --- a/src/Navigator/Actions/Status.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Navigator.Actions; - -/// -/// Represents the outcome of an action. -/// -public readonly struct Status -{ - private readonly bool _isSuccess; - - /// - /// Is success. - /// - public bool IsSuccess => _isSuccess; - - /// - /// Is error. - /// - public bool IsError => !_isSuccess; - - /// - /// Default constructor. - /// - /// - public Status(bool isSuccess) - { - _isSuccess = isSuccess; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/CommandAction.cs b/src/Navigator/Bundled/Actions/CommandAction.cs deleted file mode 100644 index 6cf159d..0000000 --- a/src/Navigator/Bundled/Actions/CommandAction.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Bundled.Actions.Messages; -using Navigator.Context.Accessor; -using Navigator.Telegram; - -namespace Navigator.Bundled.Actions; - -/// -/// Command based action. -/// -[ActionType(nameof(CommandAction))] -public abstract class CommandAction : MessageAction -{ - /// - /// Command. - /// - public readonly string Command; - - /// - /// Any arguments passed with the command. If no arguments were passed, it will be null. - /// - public readonly string? Arguments; - - /// - protected CommandAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - var botProfile = Context.BotProfile; - - Command = Message.ExtractCommand(botProfile.Username)!; - Arguments = Message.ExtractArguments(); - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/AnimationAction.cs b/src/Navigator/Bundled/Actions/Messages/AnimationAction.cs deleted file mode 100644 index f5f415a..0000000 --- a/src/Navigator/Bundled/Actions/Messages/AnimationAction.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages -{ - /// - /// Action triggered by an animation being sent. - /// - [ActionType(nameof(AnimationAction))] - public abstract class AnimationAction : MessageAction - { - /// - /// Information about the animation. - /// - public readonly Animation Animation; - - /// - protected AnimationAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - Animation = Message.Animation!; - } - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/AudioAction.cs b/src/Navigator/Bundled/Actions/Messages/AudioAction.cs deleted file mode 100644 index 8add776..0000000 --- a/src/Navigator/Bundled/Actions/Messages/AudioAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by an audio file being sent. -/// /// -[ActionType(nameof(AudioAction))] -public abstract class AudioAction : MessageAction -{ - /// - /// Audio information. - /// - public readonly Audio Audio; - - /// - protected AudioAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - Audio = Message.Audio!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/ChatMemberLeftAction.cs b/src/Navigator/Bundled/Actions/Messages/ChatMemberLeftAction.cs deleted file mode 100644 index 74ae61a..0000000 --- a/src/Navigator/Bundled/Actions/Messages/ChatMemberLeftAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a user when leaving a chat. -/// -[ActionType(nameof(ChatMemberLeftAction))] -public abstract class ChatMemberLeftAction : MessageAction -{ - /// - /// Member who left the chat. - /// - public readonly User MemberLeft; - - /// - protected ChatMemberLeftAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - MemberLeft = Message.LeftChatMember!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/ChatMembersAddedAction.cs b/src/Navigator/Bundled/Actions/Messages/ChatMembersAddedAction.cs deleted file mode 100644 index 59bee2e..0000000 --- a/src/Navigator/Bundled/Actions/Messages/ChatMembersAddedAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by users being added to a chat. -/// -[ActionType(nameof(ChatMembersAddedAction))] -public abstract class ChatMembersAddedAction : MessageAction -{ - /// - /// Array of users added to the chat. - /// - public readonly User[] MembersAdded; - - /// - protected ChatMembersAddedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - MembersAdded = Message.NewChatMembers!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/ChatPhotoChangedAction.cs b/src/Navigator/Bundled/Actions/Messages/ChatPhotoChangedAction.cs deleted file mode 100644 index 78ef301..0000000 --- a/src/Navigator/Bundled/Actions/Messages/ChatPhotoChangedAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a chat photo changing. -/// -[ActionType(nameof(ChatPhotoChangedAction))] -public abstract class ChatPhotoChangedAction : MessageAction -{ - /// - /// Array of photo sizes representing the new chat photo. - /// - public readonly PhotoSize[] NewChatPhoto; - - /// - protected ChatPhotoChangedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - NewChatPhoto = Message.NewChatPhoto!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/ChatPhotoDeletedAction.cs b/src/Navigator/Bundled/Actions/Messages/ChatPhotoDeletedAction.cs deleted file mode 100644 index 6986943..0000000 --- a/src/Navigator/Bundled/Actions/Messages/ChatPhotoDeletedAction.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a chat photo being deleted. -/// -[ActionType(nameof(ChatPhotoDeletedAction))] -public abstract class ChatPhotoDeletedAction : MessageAction -{ - /// - protected ChatPhotoDeletedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/ChatSharedAction.cs b/src/Navigator/Bundled/Actions/Messages/ChatSharedAction.cs deleted file mode 100644 index 4c4afcd..0000000 --- a/src/Navigator/Bundled/Actions/Messages/ChatSharedAction.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages -{ - /// - /// Action triggered when chat shared content. - /// - [ActionType(nameof(ChatSharedAction))] - public abstract class ChatSharedAction : MessageAction - { - /// - /// Information about the chat-shared content. - /// - public readonly ChatShared ChatShared; - - /// - protected ChatSharedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - ChatShared = Message.ChatShared!; - } - } -} diff --git a/src/Navigator/Bundled/Actions/Messages/ChatTitleChangedAction.cs b/src/Navigator/Bundled/Actions/Messages/ChatTitleChangedAction.cs deleted file mode 100644 index e1ea616..0000000 --- a/src/Navigator/Bundled/Actions/Messages/ChatTitleChangedAction.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action being triggered by a chat title changing. -/// -[ActionType(nameof(ChatTitleChangedAction))] -public abstract class ChatTitleChangedAction : MessageAction -{ - /// - /// The new title of the chat. - /// - public readonly string NewChatTitle; - - /// - protected ChatTitleChangedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - NewChatTitle = Message.NewChatTitle!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/ContactAction.cs b/src/Navigator/Bundled/Actions/Messages/ContactAction.cs deleted file mode 100644 index 26a27a9..0000000 --- a/src/Navigator/Bundled/Actions/Messages/ContactAction.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages -{ - /// - /// Action triggered by a contact being sent. - /// - [ActionType(nameof(ContactAction))] - public abstract class ContactAction : MessageAction - { - /// - /// Contact information. - /// - public readonly Contact Contact; - - /// - protected ContactAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - Contact = Message.Contact!; - } - } -} diff --git a/src/Navigator/Bundled/Actions/Messages/DiceAction.cs b/src/Navigator/Bundled/Actions/Messages/DiceAction.cs deleted file mode 100644 index 7308e62..0000000 --- a/src/Navigator/Bundled/Actions/Messages/DiceAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a Dice. -/// -[ActionType(nameof(DiceAction))] -public abstract class DiceAction : MessageAction -{ - /// - /// Information about the dice. - /// - public readonly Dice Dice; - - /// - protected DiceAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - Dice = Message.Dice!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/ForumTopicClosedAction.cs b/src/Navigator/Bundled/Actions/Messages/ForumTopicClosedAction.cs deleted file mode 100644 index 7bedc87..0000000 --- a/src/Navigator/Bundled/Actions/Messages/ForumTopicClosedAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a forum topic being closed. -/// -[ActionType(nameof(ForumTopicClosedAction))] -public abstract class ForumTopicClosedAction : MessageAction -{ - /// - /// Information about the closed forum topic. - /// - public readonly ForumTopicClosed ForumTopicClosed; - - /// - protected ForumTopicClosedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - ForumTopicClosed = Message.ForumTopicClosed!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/ForumTopicCreatedAction.cs b/src/Navigator/Bundled/Actions/Messages/ForumTopicCreatedAction.cs deleted file mode 100644 index 3e15b78..0000000 --- a/src/Navigator/Bundled/Actions/Messages/ForumTopicCreatedAction.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages -{ - /// - /// Action triggered by a forum topic being created. - /// - [ActionType(nameof(ForumTopicCreatedAction))] - public abstract class ForumTopicCreatedAction : MessageAction - { - /// - /// Information about the created forum topic. - /// - public readonly ForumTopicCreated ForumTopicCreated; - - /// - protected ForumTopicCreatedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - ForumTopicCreated = Message.ForumTopicCreated!; - } - } -} diff --git a/src/Navigator/Bundled/Actions/Messages/ForumTopicEditedAction.cs b/src/Navigator/Bundled/Actions/Messages/ForumTopicEditedAction.cs deleted file mode 100644 index cc403be..0000000 --- a/src/Navigator/Bundled/Actions/Messages/ForumTopicEditedAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a forum topic being edited. -/// -[ActionType(nameof(ForumTopicEditedAction))] -public abstract class ForumTopicEditedAction : MessageAction -{ - /// - /// Information about the edited forum topic. - /// - public readonly ForumTopicEdited ForumTopicEdited; - - /// - protected ForumTopicEditedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - ForumTopicEdited = Message.ForumTopicEdited!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/ForumTopicReopenedAction.cs b/src/Navigator/Bundled/Actions/Messages/ForumTopicReopenedAction.cs deleted file mode 100644 index 63ac7ec..0000000 --- a/src/Navigator/Bundled/Actions/Messages/ForumTopicReopenedAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a forum topic being reopened. -/// -[ActionType(nameof(ForumTopicReopenedAction))] -public abstract class ForumTopicReopenedAction : MessageAction -{ - /// - /// Information about the reopened forum topic. - /// - public readonly ForumTopicReopened ForumTopicReopened; - - /// - protected ForumTopicReopenedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - ForumTopicReopened = Message.ForumTopicReopened!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/GameAction.cs b/src/Navigator/Bundled/Actions/Messages/GameAction.cs deleted file mode 100644 index 9bc3671..0000000 --- a/src/Navigator/Bundled/Actions/Messages/GameAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a game. -/// -[ActionType(nameof(GameAction))] -public abstract class GameAction : MessageAction -{ - /// - /// Game information. - /// - public readonly Game Game; - - /// - protected GameAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - Game = Message.Game!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/GeneralForumTopicHiddenAction.cs b/src/Navigator/Bundled/Actions/Messages/GeneralForumTopicHiddenAction.cs deleted file mode 100644 index fb88258..0000000 --- a/src/Navigator/Bundled/Actions/Messages/GeneralForumTopicHiddenAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a general forum topic being hidden. -/// -[ActionType(nameof(GeneralForumTopicHiddenAction))] -public abstract class GeneralForumTopicHiddenAction : MessageAction -{ - /// - /// Information about the hidden general forum topic. - /// - public readonly GeneralForumTopicHidden GeneralForumTopicHidden; - - /// - protected GeneralForumTopicHiddenAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - GeneralForumTopicHidden = Message.GeneralForumTopicHidden!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/GeneralForumTopicUnhiddenAction.cs b/src/Navigator/Bundled/Actions/Messages/GeneralForumTopicUnhiddenAction.cs deleted file mode 100644 index ad74ce3..0000000 --- a/src/Navigator/Bundled/Actions/Messages/GeneralForumTopicUnhiddenAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a general forum topic being unhidden. -/// -[ActionType(nameof(GeneralForumTopicUnhiddenAction))] -public abstract class GeneralForumTopicUnhiddenAction : MessageAction -{ - /// - /// Information about the unhidden general forum topic. - /// - public readonly GeneralForumTopicUnhidden GeneralForumTopicUnhidden; - - /// - protected GeneralForumTopicUnhiddenAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - GeneralForumTopicUnhidden = Message.GeneralForumTopicUnhidden!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/GroupCreatedAction.cs b/src/Navigator/Bundled/Actions/Messages/GroupCreatedAction.cs deleted file mode 100644 index e033663..0000000 --- a/src/Navigator/Bundled/Actions/Messages/GroupCreatedAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a group being created. -/// -[ActionType(nameof(GroupCreatedAction))] -public abstract class GroupCreatedAction : MessageAction -{ - /// - /// Information about the created group. - /// - public readonly Chat CreatedGroup; - - /// - protected GroupCreatedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - CreatedGroup = Message.Chat; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/InvoiceAction.cs b/src/Navigator/Bundled/Actions/Messages/InvoiceAction.cs deleted file mode 100644 index 8f206e4..0000000 --- a/src/Navigator/Bundled/Actions/Messages/InvoiceAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types.Payments; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by an invoice being sent. -/// -[ActionType(nameof(InvoiceAction))] -public abstract class InvoiceAction : MessageAction -{ - /// - /// Invoice information. - /// - public readonly Invoice Invoice; - - /// - protected InvoiceAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - Invoice = Message.Invoice!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/LocationAction.cs b/src/Navigator/Bundled/Actions/Messages/LocationAction.cs deleted file mode 100644 index 7de4372..0000000 --- a/src/Navigator/Bundled/Actions/Messages/LocationAction.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages -{ - /// - /// Action triggered by a location being sent. - /// - [ActionType(nameof(LocationAction))] - public abstract class LocationAction : MessageAction - { - /// - /// Location information. - /// - public readonly Location Location; - - /// - protected LocationAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - Location = Message.Location!; // Assuming Location is a property of the Message class. - } - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/MessageAction.cs b/src/Navigator/Bundled/Actions/Messages/MessageAction.cs deleted file mode 100644 index 49b4d54..0000000 --- a/src/Navigator/Bundled/Actions/Messages/MessageAction.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// A message based action. -/// -[ActionType(nameof(MessageAction))] -public abstract class MessageAction : BaseAction -{ - /// - /// The original Message. - /// - public readonly Message Message; - - /// - /// Id of the current chat. - /// - public readonly long ChatId; - - /// - /// Timestamp of the message creation. - /// - public new readonly DateTime Timestamp; - - /// - /// Determines if this message is a reply to another message. - /// - public readonly bool IsReply; - - /// - /// Determines if this message is a forwarded message. - /// - public readonly bool IsForwarded; - - /// - protected MessageAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - var update = navigatorContextAccessor.NavigatorContext.GetUpdate(); - - Message = update.Message!; - ChatId = Context.Conversation.Chat!.Id; - Timestamp = Message.Date; - IsReply = update.Message!.ReplyToMessage is not null; - IsForwarded = update.Message.ForwardDate is not null; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/MessageAutoDeleteTimerChangedAction.cs b/src/Navigator/Bundled/Actions/Messages/MessageAutoDeleteTimerChangedAction.cs deleted file mode 100644 index 06eb5d0..0000000 --- a/src/Navigator/Bundled/Actions/Messages/MessageAutoDeleteTimerChangedAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by the auto delete timer being changed in a chat. -/// -[ActionType(nameof(MessageAutoDeleteTimerChangedAction))] -public abstract class MessageAutoDeleteTimerChangedAction : MessageAction -{ - /// - /// The new auto-delete timer duration for messages in the chat. - /// - public readonly MessageAutoDeleteTimerChanged MessageAutoDeleteTime; - - /// - protected MessageAutoDeleteTimerChangedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - MessageAutoDeleteTime = Message.MessageAutoDeleteTimerChanged!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/MessagePinnedAction.cs b/src/Navigator/Bundled/Actions/Messages/MessagePinnedAction.cs deleted file mode 100644 index ffd6d29..0000000 --- a/src/Navigator/Bundled/Actions/Messages/MessagePinnedAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a message being pinned. -/// -[ActionType(nameof(MessagePinnedAction))] -public abstract class MessagePinnedAction : MessageAction -{ - /// - /// ID of the pinned message. - /// - public readonly Message PinnedMessageId; - - /// - protected MessagePinnedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - PinnedMessageId = Message.PinnedMessage!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/MigratedFromGroupAction.cs b/src/Navigator/Bundled/Actions/Messages/MigratedFromGroupAction.cs deleted file mode 100644 index 734e842..0000000 --- a/src/Navigator/Bundled/Actions/Messages/MigratedFromGroupAction.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a chat being from a group. -/// -[ActionType(nameof(MigratedFromGroupAction))] -public abstract class MigratedFromGroupAction : MessageAction -{ - /// - /// Information about the original group before migration. - /// - public readonly Chat MigratedChat; - - /// - /// New Id for the chat. - /// - public readonly long MigrateToChatId; - - /// - protected MigratedFromGroupAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - MigratedChat = Message.Chat; - MigrateToChatId = (long)Message.MigrateToChatId!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/MigratedToSupergroupAction.cs b/src/Navigator/Bundled/Actions/Messages/MigratedToSupergroupAction.cs deleted file mode 100644 index fbc2e79..0000000 --- a/src/Navigator/Bundled/Actions/Messages/MigratedToSupergroupAction.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages -{ - /// - /// Action triggered by a chat being migrated to a supergroup. - /// - [ActionType(nameof(MigratedToSupergroupAction))] - public abstract class MigratedToSupergroupAction : MessageAction - { - /// - /// Information about the migrated supergroup. - /// - public readonly Chat MigratedChat; - - /// - /// Old Id for the chat. - /// - public readonly long MigrateFromChatId; - - /// - protected MigratedToSupergroupAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - MigratedChat = Message.Chat; - MigrateFromChatId = (long)Message.MigrateFromChatId!; - } - } -} diff --git a/src/Navigator/Bundled/Actions/Messages/PhotoAction.cs b/src/Navigator/Bundled/Actions/Messages/PhotoAction.cs deleted file mode 100644 index a686875..0000000 --- a/src/Navigator/Bundled/Actions/Messages/PhotoAction.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Navigator.Telegram; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a photo being sent. -/// /// -[ActionType(nameof(PhotoAction))] -public abstract class PhotoAction : MessageAction -{ - /// - /// Photo information. - /// - public readonly PhotoSize[] Photo; - - /// - protected PhotoAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - Photo = Message.Photo!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/PollMessageAction.cs b/src/Navigator/Bundled/Actions/Messages/PollMessageAction.cs deleted file mode 100644 index a4db601..0000000 --- a/src/Navigator/Bundled/Actions/Messages/PollMessageAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a poll -/// -[ActionType(nameof(PollMessageAction))] -public abstract class PollMessageAction : MessageAction -{ - /// - /// Information about the poll. - /// - public readonly Poll Poll; - - /// - protected PollMessageAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - Poll = Message.Poll!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/ProximityAlertTriggeredAction.cs b/src/Navigator/Bundled/Actions/Messages/ProximityAlertTriggeredAction.cs deleted file mode 100644 index 524a00f..0000000 --- a/src/Navigator/Bundled/Actions/Messages/ProximityAlertTriggeredAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a proximity alert being triggered. -/// -[ActionType(nameof(ProximityAlertTriggeredAction))] -public abstract class ProximityAlertTriggeredAction : MessageAction -{ - /// - /// Information about the triggered proximity alert. - /// - public readonly ProximityAlertTriggered ProximityAlert; - - /// - protected ProximityAlertTriggeredAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - ProximityAlert = Message.ProximityAlertTriggered!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/StickerAction.cs b/src/Navigator/Bundled/Actions/Messages/StickerAction.cs deleted file mode 100644 index fe445aa..0000000 --- a/src/Navigator/Bundled/Actions/Messages/StickerAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a sticker being sent. -/// /// -[ActionType(nameof(StickerAction))] -public abstract class StickerAction : MessageAction -{ - /// - /// Sticker. - /// - public readonly Sticker Sticker; - - /// - protected StickerAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - Sticker = Message.Sticker!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/SuccessfulPaymentAction.cs b/src/Navigator/Bundled/Actions/Messages/SuccessfulPaymentAction.cs deleted file mode 100644 index e21180b..0000000 --- a/src/Navigator/Bundled/Actions/Messages/SuccessfulPaymentAction.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types.Payments; - -namespace Navigator.Bundled.Actions.Messages -{ - /// - /// Action triggered by a successful payment. - /// - [ActionType(nameof(SuccessfulPaymentAction))] - public abstract class SuccessfulPaymentAction : MessageAction - { - /// - /// Successful payment information. - /// - public readonly SuccessfulPayment SuccessfulPayment; - - /// - protected SuccessfulPaymentAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - SuccessfulPayment = Message.SuccessfulPayment!; - } - } -} diff --git a/src/Navigator/Bundled/Actions/Messages/TextAction.cs b/src/Navigator/Bundled/Actions/Messages/TextAction.cs deleted file mode 100644 index 0e273cf..0000000 --- a/src/Navigator/Bundled/Actions/Messages/TextAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Navigator.Telegram; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a text message. -/// -[ActionType(nameof(TextAction))] -public abstract class TextAction : MessageAction -{ - /// - /// Message text. - /// - public readonly string Text; - - /// - protected TextAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - Text = Message.Text!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/VenueAction.cs b/src/Navigator/Bundled/Actions/Messages/VenueAction.cs deleted file mode 100644 index 69d755b..0000000 --- a/src/Navigator/Bundled/Actions/Messages/VenueAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a venue being sent. -/// -[ActionType(nameof(VenueAction))] -public abstract class VenueAction : MessageAction -{ - /// - /// Venue information. - /// - public readonly Venue Venue; - - /// - protected VenueAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - Venue = Message.Venue!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/VideoAction.cs b/src/Navigator/Bundled/Actions/Messages/VideoAction.cs deleted file mode 100644 index e44ac4a..0000000 --- a/src/Navigator/Bundled/Actions/Messages/VideoAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by an video file being sent. -/// /// -[ActionType(nameof(VideoAction))] -public abstract class VideoAction : MessageAction -{ - /// - /// Video information. - /// - public readonly Video Video; - - /// - protected VideoAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - Video = Message.Video!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/VideoChatEndedAction.cs b/src/Navigator/Bundled/Actions/Messages/VideoChatEndedAction.cs deleted file mode 100644 index 35ba2ca..0000000 --- a/src/Navigator/Bundled/Actions/Messages/VideoChatEndedAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a video chat being ended. -/// -[ActionType(nameof(VideoChatEndedAction))] -public abstract class VideoChatEndedAction : MessageAction -{ - /// - /// Information about the ended video chat. - /// - public readonly VideoChatEnded VideoChatEnded; - - /// - protected VideoChatEndedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - VideoChatEnded = Message.VideoChatEnded!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/VideoChatParticipantsInvitedAction.cs b/src/Navigator/Bundled/Actions/Messages/VideoChatParticipantsInvitedAction.cs deleted file mode 100644 index 16fd8e8..0000000 --- a/src/Navigator/Bundled/Actions/Messages/VideoChatParticipantsInvitedAction.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages -{ - /// - /// Action triggered by participants being invited to a video chat. - /// - [ActionType(nameof(VideoChatParticipantsInvitedAction))] - public abstract class VideoChatParticipantsInvitedAction : MessageAction - { - /// - /// Information about the participants invited to the video chat. - /// - public readonly VideoChatParticipantsInvited VideoChatParticipantsInvited; - - /// - protected VideoChatParticipantsInvitedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - VideoChatParticipantsInvited = Message.VideoChatParticipantsInvited!; - } - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/VideoChatScheduledAction.cs b/src/Navigator/Bundled/Actions/Messages/VideoChatScheduledAction.cs deleted file mode 100644 index 2029a0a..0000000 --- a/src/Navigator/Bundled/Actions/Messages/VideoChatScheduledAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a video chat being scheduled. -/// -[ActionType(nameof(VideoChatScheduledAction))] -public abstract class VideoChatScheduledAction : MessageAction -{ - /// - /// Information about the scheduled video chat. - /// - public readonly VideoChatScheduled VideoChatScheduled; - - /// - protected VideoChatScheduledAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - VideoChatScheduled = Message.VideoChatScheduled!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/VideoChatStartedAction.cs b/src/Navigator/Bundled/Actions/Messages/VideoChatStartedAction.cs deleted file mode 100644 index ed494b0..0000000 --- a/src/Navigator/Bundled/Actions/Messages/VideoChatStartedAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a video chat being started. -/// -[ActionType(nameof(VideoChatStartedAction))] -public abstract class VideoChatStartedAction : MessageAction -{ - /// - /// Information about the started video chat. - /// - public readonly VideoChatStarted VideoChatStarted; - - /// - protected VideoChatStartedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - VideoChatStarted = Message.VideoChatStarted!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/VideoNoteAction.cs b/src/Navigator/Bundled/Actions/Messages/VideoNoteAction.cs deleted file mode 100644 index ad830c6..0000000 --- a/src/Navigator/Bundled/Actions/Messages/VideoNoteAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a video note being sent. -/// -[ActionType(nameof(VideoNoteAction))] -public abstract class VideoNoteAction : MessageAction -{ - /// - /// Video note information. - /// - public readonly VideoNote VideoNote; - - /// - protected VideoNoteAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - VideoNote = Message.VideoNote!; // Assuming VideoNote is a property of the Message class. - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/VoiceAction.cs b/src/Navigator/Bundled/Actions/Messages/VoiceAction.cs deleted file mode 100644 index cacb0b2..0000000 --- a/src/Navigator/Bundled/Actions/Messages/VoiceAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a voice message being sent. -/// /// -[ActionType(nameof(VoiceAction))] -public abstract class VoiceAction : MessageAction -{ - /// - /// Voice message information. - /// - public readonly Voice Voice; - - /// - protected VoiceAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - Voice = Message.Voice!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/WebAppDataAction.cs b/src/Navigator/Bundled/Actions/Messages/WebAppDataAction.cs deleted file mode 100644 index 08f6b0c..0000000 --- a/src/Navigator/Bundled/Actions/Messages/WebAppDataAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by web app data. -/// -[ActionType(nameof(WebAppDataAction))] -public abstract class WebAppDataAction : MessageAction -{ - /// - /// Web app data information. - /// - public readonly WebAppData WebAppData; - - /// - protected WebAppDataAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - WebAppData = Message.WebAppData!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/WebsiteConnectedAction.cs b/src/Navigator/Bundled/Actions/Messages/WebsiteConnectedAction.cs deleted file mode 100644 index e061577..0000000 --- a/src/Navigator/Bundled/Actions/Messages/WebsiteConnectedAction.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered by a website being connected. -/// -[ActionType(nameof(WebsiteConnectedAction))] -public abstract class WebsiteConnectedAction : MessageAction -{ - /// - /// Entity representing the website connected. - /// - public readonly string WebsiteConnected; - - /// - protected WebsiteConnectedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - WebsiteConnected = Message.ConnectedWebsite!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Messages/WriteAccessAllowedAction.cs b/src/Navigator/Bundled/Actions/Messages/WriteAccessAllowedAction.cs deleted file mode 100644 index 65e33ea..0000000 --- a/src/Navigator/Bundled/Actions/Messages/WriteAccessAllowedAction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Messages; - -/// -/// Action triggered when write access is allowed. -/// -[ActionType(nameof(WriteAccessAllowedAction))] -public abstract class WriteAccessAllowedAction : MessageAction -{ - /// - /// Information about the allowed write access. - /// - public readonly WriteAccessAllowed WriteAccessAllowed; - - /// - protected WriteAccessAllowedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - WriteAccessAllowed = Message.WriteAccessAllowed!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/UnknownAction.cs b/src/Navigator/Bundled/Actions/UnknownAction.cs deleted file mode 100644 index d3b9d74..0000000 --- a/src/Navigator/Bundled/Actions/UnknownAction.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; - -namespace Navigator.Bundled.Actions; - -/// -/// Represents an unknown action. -/// If you are seeing this, something probably went wrong. -/// -[ActionType(nameof(UnknownAction))] -public abstract class UnknownAction : BaseAction -{ - /// - protected UnknownAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/CallbackQueryAction.cs b/src/Navigator/Bundled/Actions/Updates/CallbackQueryAction.cs deleted file mode 100644 index a68e9a7..0000000 --- a/src/Navigator/Bundled/Actions/Updates/CallbackQueryAction.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// A callback query based action. -/// -[ActionType(nameof(CallbackQueryAction))] -public abstract class CallbackQueryAction : BaseAction -{ - /// - /// The original - /// - public readonly CallbackQuery CallbackQuery; - - /// - /// The message that originated the callback query. Iy may be unavailable if the message is too old. - /// - public readonly Message? OriginalMessage; - - /// - /// Any data present on the callback query. - /// - public readonly string? Data; - - /// - /// True if the callback query is from a game. - /// - public readonly bool IsGameQuery; - - /// - protected CallbackQueryAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - var update = Context.GetUpdate(); - - CallbackQuery = update.CallbackQuery!; - OriginalMessage = CallbackQuery.Message; - Data = string.IsNullOrWhiteSpace(CallbackQuery.Data) ? CallbackQuery.Data : default; - IsGameQuery = CallbackQuery.IsGameQuery; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/ChannelCreatedAction.cs b/src/Navigator/Bundled/Actions/Updates/ChannelCreatedAction.cs deleted file mode 100644 index b15c239..0000000 --- a/src/Navigator/Bundled/Actions/Updates/ChannelCreatedAction.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// Action triggered by a Channel being created. -/// -[ActionType(nameof(ChannelCreatedAction))] -public abstract class ChannelCreatedAction : BaseAction -{ - /// - protected ChannelCreatedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/ChannelPostAction.cs b/src/Navigator/Bundled/Actions/Updates/ChannelPostAction.cs deleted file mode 100644 index 917f251..0000000 --- a/src/Navigator/Bundled/Actions/Updates/ChannelPostAction.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// Action triggered by a post being sent to a channel. -/// -[ActionType(nameof(ChannelPostAction))] -public abstract class ChannelPostAction : BaseAction -{ - /// - /// Channel post message. - /// - public Message ChannelPost { get; protected set; } - - /// - protected ChannelPostAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - var update = Context.GetUpdate(); - - ChannelPost = update.ChannelPost!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/ChatJoinRequestAction.cs b/src/Navigator/Bundled/Actions/Updates/ChatJoinRequestAction.cs deleted file mode 100644 index 565bd4b..0000000 --- a/src/Navigator/Bundled/Actions/Updates/ChatJoinRequestAction.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// Action triggered by a request to join a channel. -/// -[ActionType(nameof(ChatJoinRequestAction))] -public abstract class ChatJoinRequestAction : BaseAction -{ - /// - /// Chat join request. - /// - public ChatJoinRequest Request { get; protected set; } - - /// - protected ChatJoinRequestAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - var update = Context.GetUpdate(); - - Request = update.ChatJoinRequest!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/ChatMemberAction.cs b/src/Navigator/Bundled/Actions/Updates/ChatMemberAction.cs deleted file mode 100644 index c5142f4..0000000 --- a/src/Navigator/Bundled/Actions/Updates/ChatMemberAction.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// Action triggered when a chat member has been updated. -/// -[ActionType(nameof(ChatMemberAction))] -public abstract class ChatMemberAction : BaseAction -{ - /// - /// Chat member updated. - /// - public ChatMemberUpdated ChatMemberUpdated { get; set; } - - /// - protected ChatMemberAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - var update = Context.GetUpdate(); - - ChatMemberUpdated = update.ChatMember!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/ChosenInlineResultAction.cs b/src/Navigator/Bundled/Actions/Updates/ChosenInlineResultAction.cs deleted file mode 100644 index 63e5672..0000000 --- a/src/Navigator/Bundled/Actions/Updates/ChosenInlineResultAction.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// Inline result based action. -/// -[ActionType(nameof(ChosenInlineResultAction))] -public abstract class ChosenInlineResultAction : BaseAction -{ - /// - /// The original chosen inline result. - /// - public ChosenInlineResult ChosenInlineResult { get; protected set; } - - /// - /// The chosen result id. - /// - public string ResultId { get; protected set; } - - /// - /// The original query. - /// - public string Query { get; protected set; } - - /// - protected ChosenInlineResultAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - var update = Context.GetUpdate(); - - ChosenInlineResult = update.ChosenInlineResult!; - ResultId = update.ChosenInlineResult!.ResultId; - Query = update.ChosenInlineResult.Query; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/DocumentAction.cs b/src/Navigator/Bundled/Actions/Updates/DocumentAction.cs deleted file mode 100644 index 98db447..0000000 --- a/src/Navigator/Bundled/Actions/Updates/DocumentAction.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// Action triggered by a document being sent. -/// -[ActionType(nameof(DocumentAction))] -public abstract class DocumentAction : BaseAction -{ - /// - /// Document. - /// - public Document Document { get; set; } - - /// - public DocumentAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - var update = Context.GetUpdate(); - Document = update.Message!.Document!; - } - -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/EditedChannelPostAction.cs b/src/Navigator/Bundled/Actions/Updates/EditedChannelPostAction.cs deleted file mode 100644 index d6041b8..0000000 --- a/src/Navigator/Bundled/Actions/Updates/EditedChannelPostAction.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// Action triggered by a post sent to a channel. -/// -[ActionType(nameof(EditedChannelPostAction))] -public abstract class EditedChannelPostAction : BaseAction -{ - /// - /// Edited channel post. - /// - public Message ChannelPost { get; set; } - - /// - protected EditedChannelPostAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - ChannelPost = Context.GetUpdate().EditedChannelPost!; - } - -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/EditedMessageAction.cs b/src/Navigator/Bundled/Actions/Updates/EditedMessageAction.cs deleted file mode 100644 index e03ab19..0000000 --- a/src/Navigator/Bundled/Actions/Updates/EditedMessageAction.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// Action triggered when a message is edited. -/// -/// Caution. Does not always works. -/// -/// -[ActionType(nameof(EditedMessageAction))] -public abstract class EditedMessageAction : BaseAction -{ - /// - /// Original . - /// - public Message OriginalMessage { get; protected set; } - - /// - /// Edited . - /// - public Message EditedMessage { get; protected set; } - - /// - protected EditedMessageAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - var update = Context.GetUpdate(); - - OriginalMessage = update.Message!; - EditedMessage = update.EditedMessage!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/InlineQueryAction.cs b/src/Navigator/Bundled/Actions/Updates/InlineQueryAction.cs deleted file mode 100644 index e062e2f..0000000 --- a/src/Navigator/Bundled/Actions/Updates/InlineQueryAction.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// Inline query based action. -/// -[ActionType(nameof(InlineQueryAction))] -public abstract class InlineQueryAction : BaseAction -{ - /// - /// The original - /// - public InlineQuery InlineQuery { get; protected set; } - - /// - /// The query from the user. - /// - public string Query { get; protected set; } - - /// - /// The offset. - /// - public string Offset { get; protected set; } - - /// - protected InlineQueryAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - var update = Context.GetUpdate(); - - InlineQuery = update.InlineQuery!; - Query = update.InlineQuery!.Query; - Offset = update.InlineQuery.Offset; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/MyChatMemberAction.cs b/src/Navigator/Bundled/Actions/Updates/MyChatMemberAction.cs deleted file mode 100644 index 62af103..0000000 --- a/src/Navigator/Bundled/Actions/Updates/MyChatMemberAction.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// Action triggered when the bot’s chat member status was updated in a chat. -/// For private chats, this update is received only when the bot is blocked or unblocked by the user. -/// -[ActionType(nameof(MyChatMemberAction))] -public abstract class MyChatMemberAction : BaseAction -{ - /// - /// Chat member updated. - /// - public ChatMemberUpdated MyChatMember { get; set; } - - /// - protected MyChatMemberAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - var update = Context.GetUpdate(); - - MyChatMember = update.MyChatMember!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/PollAnswerAction.cs b/src/Navigator/Bundled/Actions/Updates/PollAnswerAction.cs deleted file mode 100644 index 4ef0368..0000000 --- a/src/Navigator/Bundled/Actions/Updates/PollAnswerAction.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// Action triggered by a poll being answered. -/// -[ActionType(nameof(PollAnswerAction))] -public abstract class PollAnswerAction : BaseAction -{ - /// - /// The original Poll. - /// - public PollAnswer Answer { get; protected set; } - - /// - protected PollAnswerAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - var update = Context.GetUpdate(); - - Answer = update.PollAnswer!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/PollUpdateAction.cs b/src/Navigator/Bundled/Actions/Updates/PollUpdateAction.cs deleted file mode 100644 index c1bf2ea..0000000 --- a/src/Navigator/Bundled/Actions/Updates/PollUpdateAction.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context.Accessor; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// Action triggered by a being updated. -/// -[ActionType(nameof(PollUpdateAction))] -public abstract class PollUpdateAction : BaseAction -{ - /// - /// The original Poll. - /// - public Poll Poll { get; protected set; } - - /// - protected PollUpdateAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - var update = Context.GetUpdate(); - - Poll = update.Poll!; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/PreCheckoutQueryAction.cs b/src/Navigator/Bundled/Actions/Updates/PreCheckoutQueryAction.cs deleted file mode 100644 index e263893..0000000 --- a/src/Navigator/Bundled/Actions/Updates/PreCheckoutQueryAction.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// Action triggered by a pre-checkout query being sent. -/// -[ActionType(nameof(PreCheckoutQueryAction))] -public abstract class PreCheckoutQueryAction : BaseAction -{ - /// - protected PreCheckoutQueryAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - } - -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/ShippingQueryAction.cs b/src/Navigator/Bundled/Actions/Updates/ShippingQueryAction.cs deleted file mode 100644 index 321e380..0000000 --- a/src/Navigator/Bundled/Actions/Updates/ShippingQueryAction.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// action triggered by a shipping query being sent. -/// -[ActionType(nameof(ShippingQueryAction))] -public abstract class ShippingQueryAction : BaseAction -{ - /// - protected ShippingQueryAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - } - -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Actions/Updates/SupergroupCreatedAction.cs b/src/Navigator/Bundled/Actions/Updates/SupergroupCreatedAction.cs deleted file mode 100644 index 89e6488..0000000 --- a/src/Navigator/Bundled/Actions/Updates/SupergroupCreatedAction.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Navigator.Actions; -using Navigator.Actions.Attributes; -using Navigator.Context.Accessor; - -namespace Navigator.Bundled.Actions.Updates; - -/// -/// Action triggered by a supergroup being created. -/// -[ActionType(nameof(SupergroupCreatedAction))] -public abstract class SupergroupCreatedAction : BaseAction -{ - /// - protected SupergroupCreatedAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - - } - -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Extensions/ActionType/NavigatorContextBuilderOptionsExtensions.cs b/src/Navigator/Bundled/Extensions/ActionType/NavigatorContextBuilderOptionsExtensions.cs deleted file mode 100644 index ac8e18f..0000000 --- a/src/Navigator/Bundled/Extensions/ActionType/NavigatorContextBuilderOptionsExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Navigator.Context.Builder.Options; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Extensions.ActionType; - -internal static class NavigatorContextBuilderOptionsExtensions -{ - #region ActionType - - private const string ActionTypeKey = "_navigator.context.options.action_type"; - - public static void SetActionType(this INavigatorContextBuilderOptions contextBuilderOptions, string actionType) - { - contextBuilderOptions.TryRegisterOption(ActionTypeKey, actionType); - - } - - public static string? GetActionType(this INavigatorContextBuilderOptions contextBuilderOptions) - { - return contextBuilderOptions.RetrieveOption(ActionTypeKey); - } - - #endregion -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Extensions/Update/NavigatorContextBuilderOptionsExtensions.cs b/src/Navigator/Bundled/Extensions/Update/NavigatorContextBuilderOptionsExtensions.cs deleted file mode 100644 index 0d989ea..0000000 --- a/src/Navigator/Bundled/Extensions/Update/NavigatorContextBuilderOptionsExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Navigator.Context.Builder.Options; - -namespace Navigator.Bundled.Extensions.Update; - -internal static class NavigatorContextBuilderOptionsExtensions -{ - private const string UpdateKey = "_navigator.context.options.update"; - - public static void GetUpdate(this INavigatorContextBuilderOptions contextBuilderOptions, global::Telegram.Bot.Types.Update update) - { - contextBuilderOptions.TryRegisterOption(UpdateKey, update); - - } - - public static global::Telegram.Bot.Types.Update? GetUpdateOrDefault(this INavigatorContextBuilderOptions contextBuilderOptions) - { - return contextBuilderOptions.RetrieveOption(UpdateKey); - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Extensions/Update/NavigatorContextExtensions.cs b/src/Navigator/Bundled/Extensions/Update/NavigatorContextExtensions.cs deleted file mode 100644 index 753680d..0000000 --- a/src/Navigator/Bundled/Extensions/Update/NavigatorContextExtensions.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Navigator.Context; -using Telegram.Bot.Types; - -namespace Navigator.Bundled.Extensions.Update; - -/// -/// Bundled extensions to . -/// -public static class NavigatorContextExtensions -{ - /// - /// Returns the . Throws an exception if not found. - /// - /// - /// - /// - public static global::Telegram.Bot.Types.Update GetUpdate(this INavigatorContext navigatorContext) - { - var update = navigatorContext.GetUpdateOrDefault(); - - return update ?? throw new NavigatorException("Update was not found."); - } - - /// - /// Returns the or null if not found. - /// - /// - /// - public static global::Telegram.Bot.Types.Update? GetUpdateOrDefault(this INavigatorContext navigatorContext) - { - var @event = navigatorContext.Extensions.GetValueOrDefault(UpdateNavigatorContextExtension.UpdateKey); - - if (@event is global::Telegram.Bot.Types.Update update) - { - return update; - } - - return default; - } -} \ No newline at end of file diff --git a/src/Navigator/Bundled/Extensions/Update/UpdateNavigatorContextExtension.cs b/src/Navigator/Bundled/Extensions/Update/UpdateNavigatorContextExtension.cs deleted file mode 100644 index c38ff86..0000000 --- a/src/Navigator/Bundled/Extensions/Update/UpdateNavigatorContextExtension.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Navigator.Context; -using Navigator.Context.Builder.Options; -using Navigator.Extensions; - -namespace Navigator.Bundled.Extensions.Update; - -internal class UpdateNavigatorContextExtension : INavigatorContextExtension -{ - public const string UpdateKey = "_navigator.extensions.update"; - - public Task Extend(INavigatorContext navigatorContext, INavigatorContextBuilderOptions builderOptions) - { - navigatorContext.Extensions.TryAdd(UpdateKey, builderOptions.GetUpdateOrDefault()); - - return Task.FromResult(navigatorContext); - } -} \ No newline at end of file diff --git a/src/Navigator/Catalog/IBotActionCatalogBuilderExtensions.cs b/src/Navigator/Catalog/BotActionCatalogExtensions.cs similarity index 82% rename from src/Navigator/Catalog/IBotActionCatalogBuilderExtensions.cs rename to src/Navigator/Catalog/BotActionCatalogExtensions.cs index c21af98..e8a2c0d 100644 --- a/src/Navigator/Catalog/IBotActionCatalogBuilderExtensions.cs +++ b/src/Navigator/Catalog/BotActionCatalogExtensions.cs @@ -1,11 +1,10 @@ using Navigator.Actions.Builder; using Navigator.Telegram; using Telegram.Bot.Types; -using Telegram.Bot.Types.Enums; namespace Navigator.Catalog; -public static class IBotActionCatalogBuilderExtensions +public static class BotActionCatalogExtensions { public static IBotActionBuilder OnCommand(this IBotActionCatalogFactory factory, string command, Delegate handler) { diff --git a/src/Navigator/Catalog/BotActionCatalogFactory.cs b/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs similarity index 100% rename from src/Navigator/Catalog/BotActionCatalogFactory.cs rename to src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs diff --git a/src/Navigator/Catalog/IBotActionCatalogFactory.cs b/src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs similarity index 100% rename from src/Navigator/Catalog/IBotActionCatalogFactory.cs rename to src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs diff --git a/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs b/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs index 2cd4552..3a18557 100644 --- a/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs +++ b/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; +using Navigator.Strategy; using Telegram.Bot.Types; namespace Navigator.Configuration; @@ -37,9 +38,9 @@ private static async Task ProcessTelegramUpdate(HttpContext context) var telegramUpdate = await ParseTelegramUpdate(context.Request); - var navigatorMiddleware = context.RequestServices.GetRequiredService(); + var strategy = context.RequestServices.GetRequiredService(); - await navigatorMiddleware.Process(telegramUpdate); + await strategy.Invoke(telegramUpdate); } private static async Task ParseTelegramUpdate(HttpRequest request) diff --git a/src/Navigator/Configuration/NavigatorRouteConfiguration.cs b/src/Navigator/Configuration/NavigatorRouteConfiguration.cs index 1537ee2..aaf6168 100644 --- a/src/Navigator/Configuration/NavigatorRouteConfiguration.cs +++ b/src/Navigator/Configuration/NavigatorRouteConfiguration.cs @@ -1,23 +1,23 @@ -using Microsoft.AspNetCore.Routing; - -namespace Navigator.Configuration; - -/// -/// Configures the route for the telegram endpoint. -/// -public class NavigatorRouteConfiguration -{ - /// - /// Endpoint Route Builder. - /// - public IEndpointRouteBuilder EndpointRouteBuilder { get; internal set; } - - /// - /// Default constructor. - /// - /// - public NavigatorRouteConfiguration(IEndpointRouteBuilder endpointRouteBuilder) - { - EndpointRouteBuilder = endpointRouteBuilder; - } -} \ No newline at end of file +// using Microsoft.AspNetCore.Routing; +// +// namespace Navigator.Configuration; +// +// /// +// /// Configures the route for the telegram endpoint. +// /// +// public class NavigatorRouteConfiguration +// { +// /// +// /// Endpoint Route Builder. +// /// +// public IEndpointRouteBuilder EndpointRouteBuilder { get; internal set; } +// +// /// +// /// Default constructor. +// /// +// /// +// public NavigatorRouteConfiguration(IEndpointRouteBuilder endpointRouteBuilder) +// { +// EndpointRouteBuilder = endpointRouteBuilder; +// } +// } \ No newline at end of file diff --git a/src/Navigator/Configuration/INavigatorOptions.cs b/src/Navigator/Configuration/Options/INavigatorOptions.cs similarity index 100% rename from src/Navigator/Configuration/INavigatorOptions.cs rename to src/Navigator/Configuration/Options/INavigatorOptions.cs diff --git a/src/Navigator/Configuration/NavigatorOptions.cs b/src/Navigator/Configuration/Options/NavigatorOptions.cs similarity index 100% rename from src/Navigator/Configuration/NavigatorOptions.cs rename to src/Navigator/Configuration/Options/NavigatorOptions.cs diff --git a/src/Navigator/Configuration/NavigatorOptionsCollectionExtensions.cs b/src/Navigator/Configuration/Options/NavigatorOptionsCollectionExtensions.cs similarity index 100% rename from src/Navigator/Configuration/NavigatorOptionsCollectionExtensions.cs rename to src/Navigator/Configuration/Options/NavigatorOptionsCollectionExtensions.cs diff --git a/src/Navigator/Context/Accessor/INavigatorContextAccessor.cs b/src/Navigator/Context/Accessor/INavigatorContextAccessor.cs deleted file mode 100644 index e4a756c..0000000 --- a/src/Navigator/Context/Accessor/INavigatorContextAccessor.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Navigator.Context.Accessor; - -/// -/// Accessor for . -/// -public interface INavigatorContextAccessor -{ - /// - /// Navigator Context. - /// - INavigatorContext NavigatorContext { get; } -} \ No newline at end of file diff --git a/src/Navigator/Context/Accessor/NavigatorContextAccessor.cs b/src/Navigator/Context/Accessor/NavigatorContextAccessor.cs deleted file mode 100644 index b1631b4..0000000 --- a/src/Navigator/Context/Accessor/NavigatorContextAccessor.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Navigator.Context.Accessor; - -internal class NavigatorContextAccessor : INavigatorContextAccessor -{ - private readonly INavigatorContextFactory _navigatorContextFactory; - - public NavigatorContextAccessor(INavigatorContextFactory navigatorContextFactory) - { - _navigatorContextFactory = navigatorContextFactory; - } - - public INavigatorContext NavigatorContext => _navigatorContextFactory.Retrieve(); -} \ No newline at end of file diff --git a/src/Navigator/Context/Builder/INavigatorContextBuilder.cs b/src/Navigator/Context/Builder/INavigatorContextBuilder.cs deleted file mode 100644 index 8c2abae..0000000 --- a/src/Navigator/Context/Builder/INavigatorContextBuilder.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Navigator.Context.Builder.Options; - -namespace Navigator.Context.Builder; - -/// -/// Navigator Context Builder. -/// -public interface INavigatorContextBuilder -{ - /// - /// Builds a and returns it. - /// - /// - /// - Task Build(Action configurationAction); -} \ No newline at end of file diff --git a/src/Navigator/Context/Builder/NavigatorContextBuilder.cs b/src/Navigator/Context/Builder/NavigatorContextBuilder.cs deleted file mode 100644 index 8cbffdd..0000000 --- a/src/Navigator/Context/Builder/NavigatorContextBuilder.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Microsoft.AspNetCore.Components; -using Microsoft.Extensions.Logging; -using Navigator.Bundled.Extensions.ActionType; -using Navigator.Bundled.Extensions.Update; -using Navigator.Client; -using Navigator.Context.Builder.Options; -using Navigator.Entities; -using Navigator.Extensions; -using Navigator.Telegram; - -namespace Navigator.Context.Builder; - -internal class NavigatorContextBuilder : INavigatorContextBuilder -{ - private readonly ILogger _logger; - private readonly IEnumerable _navigatorContextExtensions; - private readonly INavigatorContextBuilderOptions _options; - private readonly INavigatorClient _navigatorClient; - - public NavigatorContextBuilder(ILogger logger, IEnumerable navigatorContextExtensions, INavigatorClient navigatorClient) - { - _logger = logger; - _navigatorContextExtensions = navigatorContextExtensions; - _navigatorClient = navigatorClient; - - _options = new NavigatorContextBuilderOptions(); - } - - public async Task Build(Action optionsAction) - { - optionsAction.Invoke(_options); - var actionType = _options.GetActionType() ?? throw new InvalidOperationException(); - - var conversation = _options.GetUpdateOrDefault()?.GetConversation() ?? throw new NavigationException(nameof(Conversation)); - - INavigatorContext context = new NavigatorContext(_navigatorClient, await _navigatorClient.GetProfile(), actionType, conversation); - - foreach (var contextExtension in _navigatorContextExtensions) - { - context = await contextExtension.Extend(context, _options); - } - - return context; - } -} \ No newline at end of file diff --git a/src/Navigator/Context/Builder/Options/INavigatorContextBuilderOptions.cs b/src/Navigator/Context/Builder/Options/INavigatorContextBuilderOptions.cs deleted file mode 100644 index c32b2cb..0000000 --- a/src/Navigator/Context/Builder/Options/INavigatorContextBuilderOptions.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace Navigator.Context.Builder.Options; - -/// -/// Navigator Context Builder Options. -/// -public interface INavigatorContextBuilderOptions -{ - /// - /// Registers an option, fails if the option already exists. - /// - /// - /// - /// - bool TryRegisterOption(string key, object option); - - /// - /// Registers an option, overriding any option that may exist. - /// - /// - /// - void ForceRegisterOption(string key, object option); - - /// - /// Retrieves an option given a key. - /// - /// - /// - /// - TType? RetrieveOption(string key); - - /// - /// Retrieves all options. - /// - /// - Dictionary RetrieveAllOptions(); -} \ No newline at end of file diff --git a/src/Navigator/Context/Builder/Options/NavigatorContextBuilderOptions.cs b/src/Navigator/Context/Builder/Options/NavigatorContextBuilderOptions.cs deleted file mode 100644 index 676159d..0000000 --- a/src/Navigator/Context/Builder/Options/NavigatorContextBuilderOptions.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace Navigator.Context.Builder.Options; - -/// -public class NavigatorContextBuilderOptions : INavigatorContextBuilderOptions -{ - private readonly Dictionary _options; - - /// - /// Default constructor. - /// - public NavigatorContextBuilderOptions() - { - _options = new Dictionary(); - } - - /// - public bool TryRegisterOption(string key, object option) - { - return _options.TryAdd(key, option); - } - - /// - public void ForceRegisterOption(string key, object option) - { - _options.Remove(key); - - TryRegisterOption(key, option); - } - - /// - public TType? RetrieveOption(string key) - { - if (_options.TryGetValue(key, out var option)) - { - return (TType) option; - } - - return default; - } - - /// - public Dictionary RetrieveAllOptions() - { - return _options; - } -} \ No newline at end of file diff --git a/src/Navigator/Context/INavigatorContext.cs b/src/Navigator/Context/INavigatorContext.cs deleted file mode 100644 index 54dba55..0000000 --- a/src/Navigator/Context/INavigatorContext.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Navigator.Client; -using Navigator.Entities; - -namespace Navigator.Context; - -/// -/// Navigator Context. -/// -public interface INavigatorContext -{ - /// - /// Client to use for interacting with Navigator and the provider (Telegram). - /// - public INavigatorClient Client { get; } - - /// - /// Profile of the bot in form. - /// - Bot BotProfile { get; } - - /// - /// Installed extensions for - /// - Dictionary Extensions { get; } - - /// - /// Useful items stored here. - /// - Dictionary Items { get; } - - /// - /// Type of the action for this context. - /// - public string ActionType { get; } - - /// - /// Conversation related to this context. - /// - public Conversation Conversation { get; } -} \ No newline at end of file diff --git a/src/Navigator/Context/INavigatorContextFactory.cs b/src/Navigator/Context/INavigatorContextFactory.cs deleted file mode 100644 index b9b465f..0000000 --- a/src/Navigator/Context/INavigatorContextFactory.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Navigator.Context.Builder.Options; - -namespace Navigator.Context; - -/// -/// Factory for creating and retrieving implementations of -/// -public interface INavigatorContextFactory -{ - /// - /// Supplies to the factory. - /// - /// - /// - Task Supply(Action action); - - /// - /// Retrieves a finished . - /// - /// - INavigatorContext Retrieve(); -} \ No newline at end of file diff --git a/src/Navigator/Context/NavigatorContext.cs b/src/Navigator/Context/NavigatorContext.cs deleted file mode 100644 index 63b6af2..0000000 --- a/src/Navigator/Context/NavigatorContext.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Navigator.Client; -using Navigator.Entities; - -namespace Navigator.Context; - -internal class NavigatorContext : INavigatorContext -{ - public INavigatorClient Client { get; } - public Bot BotProfile { get; } - public Dictionary Extensions { get; } - public Dictionary Items { get; } - public string ActionType { get; } - public Conversation Conversation { get; } - - public NavigatorContext(INavigatorClient navigatorClient, Bot botProfile, string actionType, Conversation conversation) - { - Client = navigatorClient; - BotProfile = botProfile; - ActionType = actionType; - Conversation = conversation; - - Items = new Dictionary(); - Extensions = new Dictionary(); - } -} \ No newline at end of file diff --git a/src/Navigator/Context/NavigatorContextFactory.cs b/src/Navigator/Context/NavigatorContextFactory.cs deleted file mode 100644 index 4c89186..0000000 --- a/src/Navigator/Context/NavigatorContextFactory.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Microsoft.Extensions.Logging; -using Navigator.Context.Builder; -using Navigator.Context.Builder.Options; - -namespace Navigator.Context; - -internal class NavigatorContextFactory : INavigatorContextFactory -{ - private readonly ILogger _logger; - private readonly INavigatorContextBuilder _navigatorContextBuilder; - private INavigatorContext? NavigatorContext { get; set; } - - public NavigatorContextFactory(ILogger logger, INavigatorContextBuilder navigatorContextBuilder) - { - _logger = logger; - _navigatorContextBuilder = navigatorContextBuilder; - } - - public async Task Supply(Action action) - { - try - { - _logger.LogTrace("Building a new Context"); - - NavigatorContext = await _navigatorContextBuilder.Build(action); - } - catch (Exception e) - { - _logger.LogError(e, "Unhandled exception building Context"); - throw; - } - } - - public INavigatorContext Retrieve() - { - return NavigatorContext ?? throw new NullReferenceException(); - } -} \ No newline at end of file diff --git a/src/Navigator/Entities/Bot.cs b/src/Navigator/Entities/Bot.cs index 54af19c..9b627d5 100644 --- a/src/Navigator/Entities/Bot.cs +++ b/src/Navigator/Entities/Bot.cs @@ -1,5 +1,3 @@ -using Navigator.Context; - namespace Navigator.Entities; /// @@ -9,25 +7,16 @@ public record Bot(long Id, string FirstName) : User(Id, FirstName) { /// /// Whether the bot can join groups or not. - /// - /// Optional. Only available on - /// /// public bool? CanJoinGroups { get; init; } /// /// Whether the bot can read all group messages or not. - /// - /// Optional. Only available on - /// /// public bool? CanReadAllGroupMessages { get; init; } /// /// Whether the bot supports inline queries or not. - /// - /// Optional. Only available on - /// /// public bool? SupportsInlineQueries { get; init; } } \ No newline at end of file diff --git a/src/Navigator/Extensions/INavigatorContextExtension.cs b/src/Navigator/Extensions/INavigatorContextExtension.cs deleted file mode 100644 index 0509ec7..0000000 --- a/src/Navigator/Extensions/INavigatorContextExtension.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Navigator.Context; -using Navigator.Context.Builder.Options; - -namespace Navigator.Extensions; - -/// -/// Implement this interface to extend -/// -public interface INavigatorContextExtension -{ - /// - /// Extends . - /// - /// - /// - /// - Task Extend(INavigatorContext navigatorContext, INavigatorContextBuilderOptions builderOptions); -} \ No newline at end of file diff --git a/src/Navigator/NavigatorException.cs b/src/Navigator/NavigatorException.cs index 1a926e2..bfa9fc0 100644 --- a/src/Navigator/NavigatorException.cs +++ b/src/Navigator/NavigatorException.cs @@ -12,11 +12,6 @@ public NavigatorException() { } - /// - protected NavigatorException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - /// public NavigatorException(string? message) : base(message) { diff --git a/src/Navigator/ServiceCollectionExtensions.cs b/src/Navigator/ServiceCollectionExtensions.cs index d5d50e7..84d90f5 100644 --- a/src/Navigator/ServiceCollectionExtensions.cs +++ b/src/Navigator/ServiceCollectionExtensions.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.DependencyInjection; -using Navigator.Actions; using Navigator.Bundled.Extensions.Update; using Navigator.Catalog; using Navigator.Client; @@ -10,7 +9,6 @@ using Navigator.Extensions; using Navigator.Hosted; using Scrutor; -using Action = Navigator.Actions.Action; namespace Navigator; diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index fc9e56e..a05ee15 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -1,31 +1,26 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Navigator.Actions; -using Navigator.Bundled.Extensions.Update; using Navigator.Catalog; -using Navigator.Context; -using Navigator.Context.Accessor; +using Navigator.Client; +using Navigator.Entities; using Navigator.Strategy.Classifier; +using Navigator.Telegram; using Telegram.Bot.Types; namespace Navigator.Strategy; public class NavigatorStrategy : INavigatorStrategy { - private readonly ILogger _logger; private readonly BotActionCatalog _catalog; private readonly IUpdateClassifier _classifier; private readonly IServiceProvider _serviceProvider; - private readonly INavigatorContextAccessor _contextAccessor; - public NavigatorStrategy(ILogger logger, IBotActionCatalogFactory catalogFactory, IUpdateClassifier classifier, - IServiceProvider serviceProvider, INavigatorContextAccessor contextAccessor) + public NavigatorStrategy(IBotActionCatalogFactory catalogFactory, IUpdateClassifier classifier, + IServiceProvider serviceProvider) { - _logger = logger; _catalog = catalogFactory.Retrieve(); _classifier = classifier; _serviceProvider = serviceProvider; - _contextAccessor = contextAccessor; } public async Task Invoke(Update update) @@ -34,14 +29,14 @@ public async Task Invoke(Update update) var relevantActions = _catalog.Retrieve(actionType); - foreach (var action in await FilterActionsThatCanHandleUpdate(relevantActions)) + foreach (var action in await FilterActionsThatCanHandleUpdate(relevantActions, update)) { - await ExecuteAction(action); + await ExecuteAction(action, update); } } //TODO: rework this into IAsyncEnumerable and yield - private async Task> FilterActionsThatCanHandleUpdate(IEnumerable actions) + private async Task> FilterActionsThatCanHandleUpdate(IEnumerable actions, Update update) { var successActions = new List(); @@ -53,8 +48,12 @@ private async Task> FilterActionsThatCanHandleUpdate(IEnu { arguments.Add(inputType switch { - not null when inputType == typeof(INavigatorContext) => _contextAccessor.NavigatorContext, - not null when inputType == typeof(Update) => _contextAccessor.NavigatorContext.GetUpdate(), + not null when inputType == typeof(Update) + => update, + not null when inputType == typeof(Conversation) + => update.GetConversation(), + not null when inputType == typeof(Bot) + => await _serviceProvider.GetRequiredService().GetProfile(), not null => _serviceProvider.GetRequiredService(inputType), //TODO: this exception should never happen. _ => throw new NavigatorException() @@ -70,7 +69,7 @@ private async Task> FilterActionsThatCanHandleUpdate(IEnu return successActions; } - private async Task ExecuteAction(BotAction action) + private async Task ExecuteAction(BotAction action, Update update) { var arguments = new List(); @@ -78,8 +77,12 @@ private async Task ExecuteAction(BotAction action) { arguments.Add(inputType switch { - not null when inputType == typeof(INavigatorContext) => _contextAccessor.NavigatorContext, - not null when inputType == typeof(Update) => _contextAccessor.NavigatorContext.GetUpdate(), + not null when inputType == typeof(INavigatorContext) + => _serviceProvider.GetRequiredService().NavigatorContext, + not null when inputType == typeof(INavigatorClient) + => _serviceProvider.GetRequiredService().NavigatorContext.Client, + not null when inputType == typeof(Update) + => update, not null => _serviceProvider.GetRequiredService(inputType), //TODO: this exception should never happen. _ => throw new NavigatorException() diff --git a/src/Navigator/TelegramMiddleware.cs b/src/Navigator/TelegramMiddleware.cs deleted file mode 100644 index bfee47e..0000000 --- a/src/Navigator/TelegramMiddleware.cs +++ /dev/null @@ -1,130 +0,0 @@ -using Microsoft.Extensions.Logging; -using Navigator.Actions; -using Navigator.Bundled.Actions; -using Navigator.Bundled.Actions.Messages; -using Navigator.Bundled.Actions.Updates; -using Navigator.Bundled.Extensions.ActionType; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context; -using Telegram.Bot.Types; -using Telegram.Bot.Types.Enums; -using Telegram.Bot.Types.Payments; - -namespace Navigator; - -/// -/// Telegram Middleware. -/// -public class TelegramMiddleware -{ - private readonly ILogger _logger; - private readonly INavigatorContextFactory _navigatorContextFactory; - private readonly IActionLauncher _actionLauncher; - - /// - /// Default constructor. - /// - /// - /// - /// - public TelegramMiddleware(ILogger logger, INavigatorContextFactory navigatorContextFactory, IActionLauncher actionLauncher) - { - _logger = logger; - _navigatorContextFactory = navigatorContextFactory; - _actionLauncher = actionLauncher; - } - - /// - /// Processes an . - /// - /// - public async Task Process(Update update) - { - var actionType = DefineActionType(update); - - if (actionType is null) - { - return; - } - - await _navigatorContextFactory.Supply(builder => - { - builder.SetActionType(actionType); - builder.GetUpdate(update); - }); - - await _actionLauncher.Launch(); - } - - private static string? DefineActionType(Update update) - { - return update.Type switch - { - UpdateType.Unknown => nameof(UnknownAction), - UpdateType.Message when update.Message?.Entities?.First().Type == MessageEntityType.BotCommand => nameof(CommandAction), - UpdateType.Message => update.Message?.Type switch - { - MessageType.Unknown => nameof(UnknownAction), - MessageType.Text => nameof(TextAction), - MessageType.Photo => nameof(PhotoAction), - MessageType.Audio => nameof(AudioAction), - MessageType.Video => nameof(VideoAction), - MessageType.Voice => nameof(VoiceAction), - MessageType.Document => nameof(DocumentAction), - MessageType.Sticker => nameof(StickerAction), - MessageType.Location => nameof(LocationAction), - MessageType.Contact => nameof(ContactAction), - MessageType.Venue => nameof(VenueAction), - MessageType.Game => nameof(GameAction), - MessageType.VideoNote => nameof(VideoNoteAction), - MessageType.Invoice => nameof(InvoiceAction), - MessageType.SuccessfulPayment => nameof(SuccessfulPaymentAction), - MessageType.WebsiteConnected => nameof(WebsiteConnectedAction), - MessageType.ChatMembersAdded => nameof(ChatMembersAddedAction), - MessageType.ChatMemberLeft => nameof(ChatMemberLeftAction), - MessageType.ChatTitleChanged => nameof(ChatTitleChangedAction), - MessageType.ChatPhotoChanged => nameof(ChatPhotoChangedAction), - MessageType.MessagePinned => nameof(MessagePinnedAction), - MessageType.ChatPhotoDeleted => nameof(ChatPhotoDeletedAction), - MessageType.GroupCreated => nameof(GroupCreatedAction), - MessageType.SupergroupCreated => nameof(SupergroupCreatedAction), - MessageType.ChannelCreated => nameof(ChannelCreatedAction), - MessageType.MigratedToSupergroup => nameof(MigratedToSupergroupAction), - MessageType.MigratedFromGroup => nameof(MigratedFromGroupAction), - MessageType.Poll => nameof(PollMessageAction), - MessageType.Dice => nameof(DiceAction), - MessageType.MessageAutoDeleteTimerChanged => nameof(MessageAutoDeleteTimerChangedAction), - MessageType.ProximityAlertTriggered => nameof(ProximityAlertTriggeredAction), - MessageType.WebAppData => nameof(WebAppDataAction), - MessageType.VideoChatScheduled => nameof(VideoChatScheduledAction), - MessageType.VideoChatStarted => nameof(VideoChatStartedAction), - MessageType.VideoChatEnded => nameof(VideoChatEndedAction), - MessageType.VideoChatParticipantsInvited => nameof(VideoChatParticipantsInvitedAction), - MessageType.Animation => nameof(AnimationAction), - MessageType.ForumTopicCreated => nameof(ForumTopicCreatedAction), - MessageType.ForumTopicClosed => nameof(ForumTopicClosedAction), - MessageType.ForumTopicReopened => nameof(ForumTopicReopenedAction), - MessageType.ForumTopicEdited => nameof(ForumTopicEditedAction), - MessageType.GeneralForumTopicHidden => nameof(GeneralForumTopicHiddenAction), - MessageType.GeneralForumTopicUnhidden => nameof(GeneralForumTopicUnhiddenAction), - MessageType.WriteAccessAllowed => nameof(WriteAccessAllowedAction), - MessageType.ChatShared => nameof(ChatSharedAction), - _ => nameof(MessageAction) - }, - UpdateType.InlineQuery => nameof(InlineQueryAction), - UpdateType.ChosenInlineResult => nameof(ChosenInlineResultAction), - UpdateType.CallbackQuery => nameof(CallbackQueryAction), - UpdateType.EditedMessage => nameof(EditedMessageAction), - UpdateType.ChannelPost => nameof(ChannelPostAction), - UpdateType.EditedChannelPost => nameof(EditedChannelPostAction), - UpdateType.ShippingQuery => nameof(ShippingQueryAction), - UpdateType.PreCheckoutQuery => nameof(PreCheckoutQuery), - UpdateType.Poll => nameof(PollUpdateAction), - UpdateType.PollAnswer => nameof(PollAnswerAction), - UpdateType.MyChatMember => nameof(MyChatMemberAction), - UpdateType.ChatMember => nameof(ChatMemberAction), - UpdateType.ChatJoinRequest => nameof(ChatJoinRequestAction), - _ => default - }; - } -} \ No newline at end of file diff --git a/src/Sample/Program.cs b/src/Sample/Program.cs index 39cdf6c..0a18da3 100644 --- a/src/Sample/Program.cs +++ b/src/Sample/Program.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using Incremental.Common.Configuration; using Microsoft.AspNetCore.Builder; using Navigator; @@ -34,6 +35,15 @@ public static void Main(string[] args) // // await ctx.Client.SendTextMessageAsync(ctx.Conversation.Chat!.Id, result); // } ); + + bot.OnUpdate((int a) => + { + return a * 2; + }, async (int a) => + { + await Task.Delay(2); + return a * 3; + }); app.MapNavigator(); From 47e7cc0b56567cc464ad55e52338c7e9594879d3 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Mon, 19 Aug 2024 13:17:15 +0200 Subject: [PATCH 31/66] chore: correct property name --- src/Navigator/Actions/BotActionInformation.cs | 2 +- src/Navigator/Actions/Builder/BotActionBuilder.cs | 2 +- src/Navigator/Strategy/NavigatorStrategy.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Navigator/Actions/BotActionInformation.cs b/src/Navigator/Actions/BotActionInformation.cs index 31b255f..c02f119 100644 --- a/src/Navigator/Actions/BotActionInformation.cs +++ b/src/Navigator/Actions/BotActionInformation.cs @@ -3,7 +3,7 @@ namespace Navigator.Actions; public record BotActionInformation { public required string ActionType; - public required Type[] ConditiionInputTypes; + public required Type[] ConditionInputTypes; public required Type[] HandlerInputTypes; public required ushort Priority; public required TimeSpan? Cooldown; diff --git a/src/Navigator/Actions/Builder/BotActionBuilder.cs b/src/Navigator/Actions/Builder/BotActionBuilder.cs index a087e39..ad257b6 100644 --- a/src/Navigator/Actions/Builder/BotActionBuilder.cs +++ b/src/Navigator/Actions/Builder/BotActionBuilder.cs @@ -16,7 +16,7 @@ public BotAction Build() var information = new BotActionInformation { ActionType = _actionType, - ConditiionInputTypes = _conditionInputTypes, + ConditionInputTypes = _conditionInputTypes, HandlerInputTypes = _handlerInputTypes, Priority = _priority, Cooldown = _cooldown diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index a05ee15..7bad7cf 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -44,7 +44,7 @@ private async Task> FilterActionsThatCanHandleUpdate(IEnu { var arguments = new List(); - foreach (var inputType in action.Information.ConditiionInputTypes) + foreach (var inputType in action.Information.ConditionInputTypes) { arguments.Add(inputType switch { From 57d612213d9c27f87937e7cac911695c56c0d644 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Mon, 19 Aug 2024 13:33:17 +0200 Subject: [PATCH 32/66] feat: update NavigatorStrategy with new arguments --- src/Navigator/Strategy/NavigatorStrategy.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index 7bad7cf..8e956f5 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -46,6 +46,7 @@ private async Task> FilterActionsThatCanHandleUpdate(IEnu foreach (var inputType in action.Information.ConditionInputTypes) { + //TODO: extract method arguments.Add(inputType switch { not null when inputType == typeof(Update) @@ -77,12 +78,12 @@ private async Task ExecuteAction(BotAction action, Update update) { arguments.Add(inputType switch { - not null when inputType == typeof(INavigatorContext) - => _serviceProvider.GetRequiredService().NavigatorContext, - not null when inputType == typeof(INavigatorClient) - => _serviceProvider.GetRequiredService().NavigatorContext.Client, not null when inputType == typeof(Update) => update, + not null when inputType == typeof(Conversation) + => update.GetConversation(), + not null when inputType == typeof(Bot) + => await _serviceProvider.GetRequiredService().GetProfile(), not null => _serviceProvider.GetRequiredService(inputType), //TODO: this exception should never happen. _ => throw new NavigatorException() From d52687ea6e3efe1545d9522f7521035b84786f66 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Mon, 19 Aug 2024 13:33:57 +0200 Subject: [PATCH 33/66] feat: improve BotAction and BotActionBuilder --- src/Navigator/Actions/BotAction.cs | 22 +++++++++---------- .../Actions/Builder/BotActionBuilder.cs | 6 +++++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/Navigator/Actions/BotAction.cs b/src/Navigator/Actions/BotAction.cs index 9a7f67d..976fafb 100644 --- a/src/Navigator/Actions/BotAction.cs +++ b/src/Navigator/Actions/BotAction.cs @@ -1,14 +1,11 @@ -using Navigator.Context; -using Telegram.Bot.Types; - namespace Navigator.Actions; -public record BotAction +public sealed record BotAction { public readonly Guid Id; public readonly BotActionInformation Information; - private static Delegate Condition; - private static Delegate Handler; + private readonly Delegate Condition; + private readonly Delegate Handler; public BotAction(Guid id, BotActionInformation information, Delegate condition, Delegate handler) { @@ -20,15 +17,16 @@ public BotAction(Guid id, BotActionInformation information, Delegate condition, public async Task ExecuteCondition(params object[] args) { - var result = Handler.DynamicInvoke(args); + var result = Condition.DynamicInvoke(args); - if (result is Task task) + return result switch { - return await task; - } + Task task => await task, + bool b => b, + //TODO: specify exception + _ => throw new NavigatorException() + }; - //TODO: specify exception - throw new NavigatorException(); } public async Task ExecuteHandler(params object[] args) diff --git a/src/Navigator/Actions/Builder/BotActionBuilder.cs b/src/Navigator/Actions/Builder/BotActionBuilder.cs index ad257b6..cc47d12 100644 --- a/src/Navigator/Actions/Builder/BotActionBuilder.cs +++ b/src/Navigator/Actions/Builder/BotActionBuilder.cs @@ -28,6 +28,12 @@ public BotAction Build() public BotActionBuilder(Delegate condition, Delegate handler) { _id = Guid.NewGuid(); + + if (condition.Method.ReturnType != typeof(Task) || condition.Method.ReturnType != typeof(bool)) + { + throw new NavigatorException("The condition delegate must return Task or bool"); + } + _condition = condition; _conditionInputTypes = condition.Method.GetParameters().Select(info => info.ParameterType).ToArray(); _handler = handler; From df896207d1a0b0262397d3f99384e78276e243f5 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Mon, 19 Aug 2024 14:25:44 +0200 Subject: [PATCH 34/66] feat: update NavigatorStrategy extract method for argument resolution, add documentation --- src/Navigator/Strategy/NavigatorStrategy.cs | 73 ++++++++++++++------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index 8e956f5..60e3556 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -6,15 +6,29 @@ using Navigator.Strategy.Classifier; using Navigator.Telegram; using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; +using Chat = Navigator.Entities.Chat; namespace Navigator.Strategy; +/// +/// Implements a strategy for dynamic decision-making based on incoming updates. This strategy involves classifying updates, +/// selecting relevant actions from a catalog, and executing those actions asynchronously. +/// +/// +/// public class NavigatorStrategy : INavigatorStrategy { private readonly BotActionCatalog _catalog; private readonly IUpdateClassifier _classifier; private readonly IServiceProvider _serviceProvider; + /// + /// Initializes a new instance of . + /// + /// An instance of . + /// An instance of . + /// An instance of . public NavigatorStrategy(IBotActionCatalogFactory catalogFactory, IUpdateClassifier classifier, IServiceProvider serviceProvider) { @@ -23,6 +37,13 @@ public NavigatorStrategy(IBotActionCatalogFactory catalogFactory, IUpdateClassif _serviceProvider = serviceProvider; } + /// + /// Processes an by determining the appropriate action type, + /// retrieving relevant from the , + /// filtering those actions based on the , + /// and executing each filtered action asynchronously. + /// + /// The object to be processed. public async Task Invoke(Update update) { var actionType = await _classifier.Process(update); @@ -46,19 +67,8 @@ private async Task> FilterActionsThatCanHandleUpdate(IEnu foreach (var inputType in action.Information.ConditionInputTypes) { - //TODO: extract method - arguments.Add(inputType switch - { - not null when inputType == typeof(Update) - => update, - not null when inputType == typeof(Conversation) - => update.GetConversation(), - not null when inputType == typeof(Bot) - => await _serviceProvider.GetRequiredService().GetProfile(), - not null => _serviceProvider.GetRequiredService(inputType), - //TODO: this exception should never happen. - _ => throw new NavigatorException() - }); + var argument = await GetArgument(inputType, update, action); + arguments.Add(argument); } if (await action.ExecuteCondition(arguments)) @@ -76,20 +86,33 @@ private async Task ExecuteAction(BotAction action, Update update) foreach (var inputType in action.Information.HandlerInputTypes) { - arguments.Add(inputType switch - { - not null when inputType == typeof(Update) - => update, - not null when inputType == typeof(Conversation) - => update.GetConversation(), - not null when inputType == typeof(Bot) - => await _serviceProvider.GetRequiredService().GetProfile(), - not null => _serviceProvider.GetRequiredService(inputType), - //TODO: this exception should never happen. - _ => throw new NavigatorException() - }); + var argument = await GetArgument(inputType, update, action); + arguments.Add(argument); } await action.ExecuteHandler(arguments); } + + private async Task GetArgument(Type inputType, Update update, BotAction action) + { + var argument = inputType switch + { + not null when inputType == typeof(Update) + => update, + not null when inputType == typeof(Conversation) + => update.GetConversation(), + not null when inputType == typeof(Chat) + => update.GetChatOrDefault()!, + not null when inputType == typeof(Conversation) + => update.GetUserOrDefault()!, + not null when inputType == typeof(Bot) + => await _serviceProvider.GetRequiredService().GetProfile(), + not null when inputType == typeof(string[]) && action.Information.ActionType == $"{typeof(MessageType)}.{nameof(MessageEntityType.BotCommand)}" + => update.Message!.ExtractArguments(), + not null => _serviceProvider.GetRequiredService(inputType), + //TODO: this exception should never happen. + _ => throw new NavigatorException() + }; + return argument; + } } \ No newline at end of file From 61118407f8d57eff793463faa8f7f03f5e1506a3 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Mon, 19 Aug 2024 14:26:27 +0200 Subject: [PATCH 35/66] feat: add implicit conversion between Chat and ChatId --- src/Navigator/Entities/Chat.cs | 37 +++++++++++++------ .../Telegram/TelegramUpdateExtensions.cs | 6 +-- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/Navigator/Entities/Chat.cs b/src/Navigator/Entities/Chat.cs index 41c047d..ff629ec 100644 --- a/src/Navigator/Entities/Chat.cs +++ b/src/Navigator/Entities/Chat.cs @@ -1,7 +1,9 @@ +using Telegram.Bot.Types; + namespace Navigator.Entities; /// -/// Represents a chat. +/// Represents a Navigator Chat. /// public record Chat(long Id, Chat.ChatType Type) { @@ -17,7 +19,7 @@ public record Chat(long Id, Chat.ChatType Type) /// /// public string? Title { get; init; } - + /// /// Type of the chat, can be any of . /// @@ -29,8 +31,8 @@ public record Chat(long Id, Chat.ChatType Type) /// Optional. /// /// - public bool? IsForum { get; init; } - + public bool IsForum { get; init; } + /// /// Type of Chat. /// @@ -40,25 +42,38 @@ public enum ChatType /// Private. /// Private = 1, - + /// /// Group. /// Group = 2, - + /// /// Channel. /// - Channel = 3, - + Channel = 3, + /// /// Supergroup. /// - Supergroup = 4, - + Supergroup = 4, + /// /// Sender. /// Sender = 5 } -} + + /// + /// Implicitly converts a object to a object based on the 's Id property. + /// This allows for seamless integration between Chat objects and operations that require a . + /// + /// The object to be converted. + /// + /// A new instance initialized with the Id of the provided object. + /// + public static implicit operator ChatId(Chat chat) + { + return new ChatId(chat.Id); + } +} \ No newline at end of file diff --git a/src/Navigator/Telegram/TelegramUpdateExtensions.cs b/src/Navigator/Telegram/TelegramUpdateExtensions.cs index b01c293..5a2930a 100644 --- a/src/Navigator/Telegram/TelegramUpdateExtensions.cs +++ b/src/Navigator/Telegram/TelegramUpdateExtensions.cs @@ -23,11 +23,11 @@ internal static class TelegramUpdateExtensions return command; } - public static string? ExtractArguments(this Message message) + public static string[] ExtractArguments(this Message message) { return message.Text is not null && message.Text.Contains(' ') - ? message.Text.Remove(0, message.Text.IndexOf(' ') + 1) - : default; + ? message.Text.Remove(0, message.Text.IndexOf(' ') + 1).Split(' ') + : []; } public static User? GetUserOrDefault(this Update update) From dea90549fbeeaee73658cf30fafa1d4246ccc822 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Mon, 19 Aug 2024 14:45:05 +0200 Subject: [PATCH 36/66] feat: corrections here and there --- .../Actions/Builder/BotActionBuilder.cs | 2 +- .../NavigatorExtensionConfiguration.cs | 34 ---------------- .../Configuration/NavigatorConfiguration.cs | 11 +---- .../NavigatorOptionsCollectionExtensions.cs | 38 ------------------ src/Navigator/ServiceCollectionExtensions.cs | 40 +++---------------- 5 files changed, 7 insertions(+), 118 deletions(-) delete mode 100644 src/Navigator/Configuration/Extensions/NavigatorExtensionConfiguration.cs diff --git a/src/Navigator/Actions/Builder/BotActionBuilder.cs b/src/Navigator/Actions/Builder/BotActionBuilder.cs index cc47d12..2b2e6eb 100644 --- a/src/Navigator/Actions/Builder/BotActionBuilder.cs +++ b/src/Navigator/Actions/Builder/BotActionBuilder.cs @@ -29,7 +29,7 @@ public BotActionBuilder(Delegate condition, Delegate handler) { _id = Guid.NewGuid(); - if (condition.Method.ReturnType != typeof(Task) || condition.Method.ReturnType != typeof(bool)) + if (!(condition.Method.ReturnType != typeof(Task) || condition.Method.ReturnType != typeof(bool))) { throw new NavigatorException("The condition delegate must return Task or bool"); } diff --git a/src/Navigator/Configuration/Extensions/NavigatorExtensionConfiguration.cs b/src/Navigator/Configuration/Extensions/NavigatorExtensionConfiguration.cs deleted file mode 100644 index e3dd963..0000000 --- a/src/Navigator/Configuration/Extensions/NavigatorExtensionConfiguration.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace Navigator.Configuration.Extensions; - -/// -/// Provides a entry point for configuring new extensions for Navigator. -/// -public class NavigatorExtensionConfiguration -{ - private readonly NavigatorConfiguration _navigatorConfiguration; - - /// - /// Default constructor for . - /// - /// - public NavigatorExtensionConfiguration(NavigatorConfiguration navigatorConfiguration) - { - _navigatorConfiguration = navigatorConfiguration; - } - - /// - /// Configure a new extension using this method. - /// - /// - /// - public NavigatorConfiguration Extension(Action<(NavigatorOptions Options, IServiceCollection Services)> configuration) - { - configuration.Invoke((_navigatorConfiguration.Options, _navigatorConfiguration.Services)); - - _navigatorConfiguration.RegisterOrReplaceOptions(); - - return _navigatorConfiguration; - } -} \ No newline at end of file diff --git a/src/Navigator/Configuration/NavigatorConfiguration.cs b/src/Navigator/Configuration/NavigatorConfiguration.cs index 9deb5e8..84ca0be 100644 --- a/src/Navigator/Configuration/NavigatorConfiguration.cs +++ b/src/Navigator/Configuration/NavigatorConfiguration.cs @@ -1,6 +1,5 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -using Navigator.Configuration.Extensions; namespace Navigator.Configuration; @@ -9,11 +8,6 @@ namespace Navigator.Configuration; /// public class NavigatorConfiguration { - /// - /// Configures an extension for Navigator. - /// - public NavigatorExtensionConfiguration WithExtension { get; internal set; } - /// /// Gets the that are being used. /// @@ -43,11 +37,8 @@ public NavigatorConfiguration(Action options, IServiceCollecti Services = services; services.AddSingleton(Options); - - WithExtension = new NavigatorExtensionConfiguration(this); } - - + /// /// Registers the or replaces it if already exists. /// diff --git a/src/Navigator/Configuration/Options/NavigatorOptionsCollectionExtensions.cs b/src/Navigator/Configuration/Options/NavigatorOptionsCollectionExtensions.cs index 0461294..974443f 100644 --- a/src/Navigator/Configuration/Options/NavigatorOptionsCollectionExtensions.cs +++ b/src/Navigator/Configuration/Options/NavigatorOptionsCollectionExtensions.cs @@ -93,44 +93,6 @@ public static bool MultipleActionsUsageIsEnabled(this INavigatorOptions navigato #endregion - #region ActionsAssemblies - - private const string ActionsAssembliesKey = "_navigator.options.actions_assemblies"; - - /// - /// Registers assemblies on which actions are available. - /// - /// - /// - public static void RegisterActionsFromAssemblies(this NavigatorOptions navigatorOptions, params Assembly[] assemblies) - { - var registeredAssemblies = navigatorOptions.RetrieveOption(ActionsAssembliesKey); - - if (registeredAssemblies?.Length > 0) - { - var combinedAssemblies = new List(registeredAssemblies); - combinedAssemblies.AddRange(assemblies); - - navigatorOptions.TryRegisterOption(ActionsAssembliesKey, combinedAssemblies); - } - else - { - navigatorOptions.TryRegisterOption(ActionsAssembliesKey, assemblies); - } - } - - /// - /// Returns the registered assemblies. - /// - /// - /// - public static Assembly[] GetActionsAssemblies(this INavigatorOptions navigatorOptions) - { - return navigatorOptions.RetrieveOption(ActionsAssembliesKey) ?? new[] { Assembly.GetCallingAssembly() }; - } - - #endregion - #region TelegramToken private const string TelegramTokenKey = "_navigator.options.telegram_token"; diff --git a/src/Navigator/ServiceCollectionExtensions.cs b/src/Navigator/ServiceCollectionExtensions.cs index 84d90f5..81b3a70 100644 --- a/src/Navigator/ServiceCollectionExtensions.cs +++ b/src/Navigator/ServiceCollectionExtensions.cs @@ -1,13 +1,10 @@ using Microsoft.Extensions.DependencyInjection; -using Navigator.Bundled.Extensions.Update; using Navigator.Catalog; using Navigator.Client; using Navigator.Configuration; -using Navigator.Context; -using Navigator.Context.Accessor; -using Navigator.Context.Builder; -using Navigator.Extensions; using Navigator.Hosted; +using Navigator.Strategy; +using Navigator.Strategy.Classifier; using Scrutor; namespace Navigator; @@ -33,44 +30,17 @@ public static NavigatorConfiguration AddNavigator(this IServiceCollection servic var navigatorBuilder = new NavigatorConfiguration(options, services); - services.AddNavigatorContextServices(); - - services.AddScoped(); - services.AddScoped(); - - services.AddScoped(); services.AddSingleton(); - services.AddScoped(); - - services.AddHostedService(); + services.AddScoped(); + services.AddScoped(); - services.Scan(scan => scan - .FromAssemblies(navigatorBuilder.Options.GetActionsAssemblies()) - .AddClasses(classes => classes.AssignableTo()) - .UsingRegistrationStrategy(RegistrationStrategy.Append) - .AsSelf() - .WithScopedLifetime()); - - navigatorBuilder.Options.RegisterActionsCore(services - .Where(descriptor => descriptor.ImplementationType?.IsAssignableTo(typeof(Action)) ?? false) - .Select(descriptor => descriptor.ImplementationType!)); - - navigatorBuilder.Options.RegisterActionsPriorityCore(services - .Where(descriptor => descriptor.ImplementationType?.IsAssignableTo(typeof(Action)) ?? false) - .Select(descriptor => descriptor.ImplementationType!)); + services.AddHostedService(); navigatorBuilder.RegisterOrReplaceOptions(); return navigatorBuilder; } - - internal static void AddNavigatorContextServices(this IServiceCollection services) - { - services.AddScoped(); - services.AddScoped(); - services.AddTransient(); - } } \ No newline at end of file From 75301372ce1b4d59f6500b8dc6d7c022de9896d1 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Mon, 19 Aug 2024 14:45:14 +0200 Subject: [PATCH 37/66] feat: update sample --- src/Sample/Actions/EchoAction.cs | 27 --------------------------- src/Sample/Program.cs | 21 +++++++-------------- 2 files changed, 7 insertions(+), 41 deletions(-) delete mode 100644 src/Sample/Actions/EchoAction.cs diff --git a/src/Sample/Actions/EchoAction.cs b/src/Sample/Actions/EchoAction.cs deleted file mode 100644 index bf05500..0000000 --- a/src/Sample/Actions/EchoAction.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Navigator.Actions; -using Navigator.Bundled.Extensions.Update; -using Navigator.Context.Accessor; -using Telegram.Bot; - -namespace Sample.Actions; - -public record EchoAction : Action -{ - public EchoAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - } - - public override bool CanHandleCurrentContext(CancellationToken cancellationToken = default) - { - return !string.IsNullOrWhiteSpace(Context.GetUpdate().Message!.Text); - } - - public override async Task Handle(CancellationToken cancellationToken = default) - { - await Context.Client.SendTextMessageAsync(action.ChatId, action.Text, cancellationToken: cancellationToken); - - return Success(); - } -} \ No newline at end of file diff --git a/src/Sample/Program.cs b/src/Sample/Program.cs index 0a18da3..b86a392 100644 --- a/src/Sample/Program.cs +++ b/src/Sample/Program.cs @@ -4,7 +4,10 @@ using Incremental.Common.Configuration; using Microsoft.AspNetCore.Builder; using Navigator; +using Navigator.Catalog; +using Navigator.Client; using Navigator.Configuration; +using Navigator.Entities; using Telegram.Bot; namespace Sample; @@ -20,7 +23,6 @@ public static void Main(string[] args) builder.Services.AddNavigator(options => { options.SetWebHookBaseUrl(builder.Configuration["BASE_WEBHOOK_URL"]!); - options.RegisterActionsFromAssemblies(AppDomain.CurrentDomain.GetAssemblies()); options.SetTelegramToken(builder.Configuration["TELEGRAM_TOKEN"]!); options.EnableTypingNotification(); }); @@ -29,20 +31,11 @@ public static void Main(string[] args) var bot = app.GetBot(); - // bot.OnCommand("join", async (ctx, parameters) => - // { - // var result = string.Join(' ', parameters); - // - // await ctx.Client.SendTextMessageAsync(ctx.Conversation.Chat!.Id, result); - // } ); - - bot.OnUpdate((int a) => - { - return a * 2; - }, async (int a) => + bot.OnCommand("join", async (INavigatorClient client, Chat chat, string[] parameters) => { - await Task.Delay(2); - return a * 3; + var result = string.Join(' ', parameters); + + await client.SendTextMessageAsync(chat, result); }); app.MapNavigator(); From 5d05150eab5f0c1d6320b0e937cc85c4f01c412e Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Mon, 19 Aug 2024 16:42:08 +0200 Subject: [PATCH 38/66] feat: refactor and improve action types to update categories --- src/Navigator/Actions/BotActionInformation.cs | 17 +- .../Actions/Builder/BotActionBuilder.cs | 10 +- .../Actions/Builder/IBotActionBuilder.cs | 2 +- src/Navigator/Catalog/BotActionCatalog.cs | 16 +- .../Catalog/BotActionCatalogExtensions.cs | 15 -- .../Factory/BotActionCatalogFactory.cs | 2 +- .../BotActionCatalogFactoryExtensions.cs | 50 ++++++ .../Factory/IBotActionCatalogFactory.cs | 9 - .../Strategy/Classifier/IUpdateClassifier.cs | 167 +++++++++--------- src/Navigator/Strategy/NavigatorStrategy.cs | 2 +- src/Sample/Program.cs | 5 +- 11 files changed, 164 insertions(+), 131 deletions(-) delete mode 100644 src/Navigator/Catalog/BotActionCatalogExtensions.cs create mode 100644 src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs diff --git a/src/Navigator/Actions/BotActionInformation.cs b/src/Navigator/Actions/BotActionInformation.cs index c02f119..a498a67 100644 --- a/src/Navigator/Actions/BotActionInformation.cs +++ b/src/Navigator/Actions/BotActionInformation.cs @@ -2,9 +2,24 @@ namespace Navigator.Actions; public record BotActionInformation { - public required string ActionType; + public required UpdateCategory Category; public required Type[] ConditionInputTypes; public required Type[] HandlerInputTypes; public required ushort Priority; public required TimeSpan? Cooldown; +} + +public sealed record UpdateCategory(string Kind, string? Subkind = default) +{ + /// + public bool Equals(UpdateCategory? other) + { + return Kind == other?.Kind && (Subkind == null || other.Subkind == null || Subkind == other.Subkind); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(Kind, Subkind); + } } \ No newline at end of file diff --git a/src/Navigator/Actions/Builder/BotActionBuilder.cs b/src/Navigator/Actions/Builder/BotActionBuilder.cs index 2b2e6eb..283ec05 100644 --- a/src/Navigator/Actions/Builder/BotActionBuilder.cs +++ b/src/Navigator/Actions/Builder/BotActionBuilder.cs @@ -1,3 +1,5 @@ +using Telegram.Bot.Types.Enums; + namespace Navigator.Actions.Builder; public class BotActionBuilder : IBotActionBuilder @@ -7,7 +9,7 @@ public class BotActionBuilder : IBotActionBuilder private readonly Delegate _handler; private readonly Type[] _conditionInputTypes; private readonly Type[] _handlerInputTypes; - private string _actionType { get; set; } + private UpdateCategory _category { get; set; } private ushort _priority { get; set; } private TimeSpan? _cooldown { get; set; } @@ -15,7 +17,7 @@ public BotAction Build() { var information = new BotActionInformation { - ActionType = _actionType, + Category = _category, ConditionInputTypes = _conditionInputTypes, HandlerInputTypes = _handlerInputTypes, Priority = _priority, @@ -53,9 +55,9 @@ public IBotActionBuilder WithCooldown(TimeSpan cooldown) return this; } - public IBotActionBuilder SetType(string type) + public IBotActionBuilder SetType(UpdateCategory category) { - _actionType = type; + _category = category; return this; } } \ No newline at end of file diff --git a/src/Navigator/Actions/Builder/IBotActionBuilder.cs b/src/Navigator/Actions/Builder/IBotActionBuilder.cs index 0a93384..b53999b 100644 --- a/src/Navigator/Actions/Builder/IBotActionBuilder.cs +++ b/src/Navigator/Actions/Builder/IBotActionBuilder.cs @@ -5,5 +5,5 @@ public interface IBotActionBuilder public BotAction Build(); public IBotActionBuilder WithPriority(ushort priority); public IBotActionBuilder WithCooldown(TimeSpan cooldown); - public IBotActionBuilder SetType(string type); + public IBotActionBuilder SetType(UpdateCategory category); } \ No newline at end of file diff --git a/src/Navigator/Catalog/BotActionCatalog.cs b/src/Navigator/Catalog/BotActionCatalog.cs index 40f959c..e0193be 100644 --- a/src/Navigator/Catalog/BotActionCatalog.cs +++ b/src/Navigator/Catalog/BotActionCatalog.cs @@ -6,26 +6,18 @@ public record BotActionCatalog { protected readonly Dictionary Actions; protected readonly Dictionary PriorityByAction; - protected readonly Dictionary ActionsByType; public BotActionCatalog(IList actions) { Actions = actions.ToDictionary(action => action.Id); PriorityByAction = actions.ToDictionary(action => action.Id, action => action.Information.Priority); - ActionsByType = actions.GroupBy(action => action.Information.ActionType) - .ToDictionary(grouping => grouping.Key, grouping => grouping.Select(action => action.Id).ToArray()); } //TODO: rework this into IAsyncEnumerable and yield - public IEnumerable Retrieve(string type) + public IEnumerable Retrieve(UpdateCategory category) { - if (ActionsByType.TryGetValue(type, out var filtered) is false) - { - return []; - } - - var actions = filtered.Select(id => Actions[id]).OrderBy(action => PriorityByAction[action.Id]); - - return actions; + return Actions.Values + .Where(action => action.Information.Category == category) + .OrderBy(action => PriorityByAction[action.Id]); } } \ No newline at end of file diff --git a/src/Navigator/Catalog/BotActionCatalogExtensions.cs b/src/Navigator/Catalog/BotActionCatalogExtensions.cs deleted file mode 100644 index e8a2c0d..0000000 --- a/src/Navigator/Catalog/BotActionCatalogExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Navigator.Actions.Builder; -using Navigator.Telegram; -using Telegram.Bot.Types; - -namespace Navigator.Catalog; - -public static class BotActionCatalogExtensions -{ - public static IBotActionBuilder OnCommand(this IBotActionCatalogFactory factory, string command, Delegate handler) - { - var actionBuilder = factory.OnUpdate((Update update) => update.Message?.ExtractCommand() == command, handler); - - return actionBuilder; - } -} \ No newline at end of file diff --git a/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs b/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs index 003d228..a2081c7 100644 --- a/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs +++ b/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs @@ -15,7 +15,7 @@ public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler) var id = Guid.NewGuid(); var actionBuilder = new BotActionBuilder(condition, handler); - actionBuilder.SetType($"{typeof(UpdateType)}.{nameof(UpdateType.Unknown)}"); + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Unknown))); Actions.Add(actionBuilder); diff --git a/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs b/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs new file mode 100644 index 0000000..3858d16 --- /dev/null +++ b/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs @@ -0,0 +1,50 @@ +using Navigator.Actions; +using Navigator.Actions.Builder; +using Navigator.Client; +using Navigator.Telegram; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; + +namespace Navigator.Catalog.Factory.Extensions; + +public static class BotActionCatalogFactoryExtensions +{ + // public static IBotActionBuilder OnUpdate(this IBotActionCatalogFactory factory, Func> condition, Delegate handler) + // { + // var actionBuilder = factory.OnUpdate(condition, handler); + // + // return actionBuilder; + // } + // + // public static IBotActionBuilder OnUpdate(this IBotActionCatalogFactory factory, Func> condition, + // Func handler) + // { + // var actionBuilder = factory.OnUpdate(condition, handler); + // + // return actionBuilder; + // } + // + // public static IBotActionBuilder OnUpdate(this IBotActionCatalogFactory factory, Func condition, Delegate handler) + // { + // var actionBuilder = factory.OnUpdate(condition, handler); + // + // return actionBuilder; + // } + // + // public static IBotActionBuilder OnUpdate(this IBotActionCatalogFactory factory, Func condition, + // Func handler) + // { + // var actionBuilder = factory.OnUpdate(condition, handler); + // + // return actionBuilder; + // } + + public static IBotActionBuilder OnCommand(this IBotActionCatalogFactory factory, string command, Delegate handler) + { + var actionBuilder = factory.OnUpdate((Update update) => update.Message?.ExtractCommand() == command, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageEntityType.BotCommand))); + + return actionBuilder; + } +} \ No newline at end of file diff --git a/src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs b/src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs index 8d9dfc3..c9f2028 100644 --- a/src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs +++ b/src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs @@ -7,13 +7,4 @@ public interface IBotActionCatalogFactory public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler); public BotActionCatalog Retrieve(); - // public IBotActionBuilder OnUpdate(Func> condition, Delegate handler); - // public IBotActionBuilder OnUpdate(Func> condition, Action handler); - // public IBotActionBuilder OnUpdate(Func> condition, Func handler); - // public IBotActionBuilder OnUpdate(Func condition, Delegate handler); - // public IBotActionBuilder OnUpdate(Func condition, Action handler); - // public IBotActionBuilder OnUpdate(Func condition, Func handler); - - - // public NavigatorBotBuilder OnCommand(string command, Func action); } \ No newline at end of file diff --git a/src/Navigator/Strategy/Classifier/IUpdateClassifier.cs b/src/Navigator/Strategy/Classifier/IUpdateClassifier.cs index c6236e9..447d602 100644 --- a/src/Navigator/Strategy/Classifier/IUpdateClassifier.cs +++ b/src/Navigator/Strategy/Classifier/IUpdateClassifier.cs @@ -1,3 +1,4 @@ +using Navigator.Actions; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -5,100 +6,100 @@ namespace Navigator.Strategy.Classifier; public interface IUpdateClassifier { - Task Process(Update update); + Task Process(Update update); } public class UpdateClassifier : IUpdateClassifier { - public Task Process(Update update) + public Task Process(Update update) { return Task.FromResult(update.Type switch { - UpdateType.Unknown => $"{typeof(UpdateType)}.{nameof(UpdateType.Unknown)}", + UpdateType.Unknown => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Unknown)), UpdateType.Message when update.Message?.Entities?.First().Type == MessageEntityType.BotCommand - => $"{typeof(MessageType)}.{nameof(MessageEntityType.BotCommand)}", + => new UpdateCategory(nameof(MessageType), nameof(MessageEntityType.BotCommand)), UpdateType.Message => update.Message?.Type switch { - MessageType.Unknown => $"{typeof(MessageType)}.{nameof(MessageType.Unknown)}", - MessageType.Text => $"{typeof(MessageType)}.{nameof(MessageType.Text)}", - MessageType.Photo => $"{typeof(MessageType)}.{nameof(MessageType.Photo)}", - MessageType.Audio => $"{typeof(MessageType)}.{nameof(MessageType.Audio)}", - MessageType.Video => $"{typeof(MessageType)}.{nameof(MessageType.Video)}", - MessageType.Voice => $"{typeof(MessageType)}.{nameof(MessageType.Voice)}", - MessageType.Document => $"{typeof(MessageType)}.{nameof(MessageType.Document)}", - MessageType.Sticker => $"{typeof(MessageType)}.{nameof(MessageType.Sticker)}", - MessageType.Location => $"{typeof(MessageType)}.{nameof(MessageType.Location)}", - MessageType.Contact => $"{typeof(MessageType)}.{nameof(MessageType.Contact)}", - MessageType.Venue => $"{typeof(MessageType)}.{nameof(MessageType.Venue)}", - MessageType.Game => $"{typeof(MessageType)}.{nameof(MessageType.Game)}", - MessageType.VideoNote => $"{typeof(MessageType)}.{nameof(MessageType.VideoNote)}", - MessageType.Invoice => $"{typeof(MessageType)}.{nameof(MessageType.Invoice)}", - MessageType.SuccessfulPayment => $"{typeof(MessageType)}.{nameof(MessageType.SuccessfulPayment)}", - MessageType.ConnectedWebsite => $"{typeof(MessageType)}.{nameof(MessageType.ConnectedWebsite)}", - MessageType.NewChatMembers => $"{typeof(MessageType)}.{nameof(MessageType.NewChatMembers)}", - MessageType.LeftChatMember => $"{typeof(MessageType)}.{nameof(MessageType.LeftChatMember)}", - MessageType.NewChatTitle => $"{typeof(MessageType)}.{nameof(MessageType.NewChatTitle)}", - MessageType.NewChatPhoto => $"{typeof(MessageType)}.{nameof(MessageType.NewChatPhoto)}", - MessageType.PinnedMessage => $"{typeof(MessageType)}.{nameof(MessageType.PinnedMessage)}", - MessageType.DeleteChatPhoto => $"{typeof(MessageType)}.{nameof(MessageType.DeleteChatPhoto)}", - MessageType.GroupChatCreated => $"{typeof(MessageType)}.{nameof(MessageType.GroupChatCreated)}", - MessageType.SupergroupChatCreated => $"{typeof(MessageType)}.{nameof(MessageType.SupergroupChatCreated)}", - MessageType.ChannelChatCreated => $"{typeof(MessageType)}.{nameof(MessageType.ChannelChatCreated)}", - MessageType.MigrateFromChatId => $"{typeof(MessageType)}.{nameof(MessageType.MigrateFromChatId)}", - MessageType.MigrateToChatId => $"{typeof(MessageType)}.{nameof(MessageType.MigrateToChatId)}", - MessageType.Poll => $"{typeof(MessageType)}.{nameof(MessageType.Poll)}", - MessageType.Dice => $"{typeof(MessageType)}.{nameof(MessageType.Dice)}", - MessageType.MessageAutoDeleteTimerChanged => $"{typeof(MessageType)}.{nameof(MessageType.MessageAutoDeleteTimerChanged)}", - MessageType.ProximityAlertTriggered => $"{typeof(MessageType)}.{nameof(MessageType.ProximityAlertTriggered)}", - MessageType.WebAppData => $"{typeof(MessageType)}.{nameof(MessageType.WebAppData)}", - MessageType.VideoChatScheduled => $"{typeof(MessageType)}.{nameof(MessageType.VideoChatScheduled)}", - MessageType.VideoChatStarted => $"{typeof(MessageType)}.{nameof(MessageType.VideoChatStarted)}", - MessageType.VideoChatEnded => $"{typeof(MessageType)}.{nameof(MessageType.VideoChatEnded)}", - MessageType.VideoChatParticipantsInvited => $"{typeof(MessageType)}.{nameof(MessageType.VideoChatParticipantsInvited)}", - MessageType.Animation => $"{typeof(MessageType)}.{nameof(MessageType.Animation)}", - MessageType.ForumTopicCreated => $"{typeof(MessageType)}.{nameof(MessageType.ForumTopicCreated)}", - MessageType.ForumTopicClosed => $"{typeof(MessageType)}.{nameof(MessageType.ForumTopicClosed)}", - MessageType.ForumTopicReopened => $"{typeof(MessageType)}.{nameof(MessageType.ForumTopicReopened)}", - MessageType.ForumTopicEdited => $"{typeof(MessageType)}.{nameof(MessageType.ForumTopicEdited)}", - MessageType.GeneralForumTopicHidden => $"{typeof(MessageType)}.{nameof(MessageType.GeneralForumTopicHidden)}", - MessageType.GeneralForumTopicUnhidden => $"{typeof(MessageType)}.{nameof(MessageType.GeneralForumTopicUnhidden)}", - MessageType.WriteAccessAllowed => $"{typeof(MessageType)}.{nameof(MessageType.WriteAccessAllowed)}", - MessageType.UsersShared => $"{typeof(MessageType)}.{nameof(MessageType.UsersShared)}", - MessageType.ChatShared => $"{typeof(MessageType)}.{nameof(MessageType.ChatShared)}", - MessageType.Story => $"{typeof(MessageType)}.{nameof(MessageType.Story)}", - MessageType.PassportData => $"{typeof(MessageType)}.{nameof(MessageType.PassportData)}", - MessageType.GiveawayCreated => $"{typeof(MessageType)}.{nameof(MessageType.GiveawayCreated)}", - MessageType.Giveaway => $"{typeof(MessageType)}.{nameof(MessageType.Giveaway)}", - MessageType.GiveawayWinners => $"{typeof(MessageType)}.{nameof(MessageType.GiveawayWinners)}", - MessageType.GiveawayCompleted => $"{typeof(MessageType)}.{nameof(MessageType.GiveawayCompleted)}", - MessageType.BoostAdded => $"{typeof(MessageType)}.{nameof(MessageType.BoostAdded)}", - MessageType.ChatBackgroundSet => $"{typeof(MessageType)}.{nameof(MessageType.ChatBackgroundSet)}", - MessageType.PaidMedia => $"{typeof(MessageType)}.{nameof(MessageType.PaidMedia)}", - MessageType.RefundedPayment => $"{typeof(MessageType)}.{nameof(MessageType.RefundedPayment)}", - _ => $"{typeof(MessageType)}.{nameof(MessageType.Unknown)}" + MessageType.Unknown => new UpdateCategory(nameof(MessageType), nameof(MessageType.Unknown)), + MessageType.Text => new UpdateCategory(nameof(MessageType), nameof(MessageType.Text)), + MessageType.Photo => new UpdateCategory(nameof(MessageType), nameof(MessageType.Photo)), + MessageType.Audio => new UpdateCategory(nameof(MessageType), nameof(MessageType.Audio)), + MessageType.Video => new UpdateCategory(nameof(MessageType), nameof(MessageType.Video)), + MessageType.Voice => new UpdateCategory(nameof(MessageType), nameof(MessageType.Voice)), + MessageType.Document => new UpdateCategory(nameof(MessageType), nameof(MessageType.Document)), + MessageType.Sticker => new UpdateCategory(nameof(MessageType), nameof(MessageType.Sticker)), + MessageType.Location => new UpdateCategory(nameof(MessageType), nameof(MessageType.Location)), + MessageType.Contact => new UpdateCategory(nameof(MessageType), nameof(MessageType.Contact)), + MessageType.Venue => new UpdateCategory(nameof(MessageType), nameof(MessageType.Venue)), + MessageType.Game => new UpdateCategory(nameof(MessageType), nameof(MessageType.Game)), + MessageType.VideoNote => new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoNote)), + MessageType.Invoice => new UpdateCategory(nameof(MessageType), nameof(MessageType.Invoice)), + MessageType.SuccessfulPayment => new UpdateCategory(nameof(MessageType), nameof(MessageType.SuccessfulPayment)), + MessageType.ConnectedWebsite => new UpdateCategory(nameof(MessageType), nameof(MessageType.ConnectedWebsite)), + MessageType.NewChatMembers => new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatMembers)), + MessageType.LeftChatMember => new UpdateCategory(nameof(MessageType), nameof(MessageType.LeftChatMember)), + MessageType.NewChatTitle => new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatTitle)), + MessageType.NewChatPhoto => new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatPhoto)), + MessageType.PinnedMessage => new UpdateCategory(nameof(MessageType), nameof(MessageType.PinnedMessage)), + MessageType.DeleteChatPhoto => new UpdateCategory(nameof(MessageType), nameof(MessageType.DeleteChatPhoto)), + MessageType.GroupChatCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.GroupChatCreated)), + MessageType.SupergroupChatCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.SupergroupChatCreated)), + MessageType.ChannelChatCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.ChannelChatCreated)), + MessageType.MigrateFromChatId => new UpdateCategory(nameof(MessageType), nameof(MessageType.MigrateFromChatId)), + MessageType.MigrateToChatId => new UpdateCategory(nameof(MessageType), nameof(MessageType.MigrateToChatId)), + MessageType.Poll => new UpdateCategory(nameof(MessageType), nameof(MessageType.Poll)), + MessageType.Dice => new UpdateCategory(nameof(MessageType), nameof(MessageType.Dice)), + MessageType.MessageAutoDeleteTimerChanged => new UpdateCategory(nameof(MessageType), nameof(MessageType.MessageAutoDeleteTimerChanged)), + MessageType.ProximityAlertTriggered => new UpdateCategory(nameof(MessageType), nameof(MessageType.ProximityAlertTriggered)), + MessageType.WebAppData => new UpdateCategory(nameof(MessageType), nameof(MessageType.WebAppData)), + MessageType.VideoChatScheduled => new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatScheduled)), + MessageType.VideoChatStarted => new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatStarted)), + MessageType.VideoChatEnded => new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatEnded)), + MessageType.VideoChatParticipantsInvited => new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatParticipantsInvited)), + MessageType.Animation => new UpdateCategory(nameof(MessageType), nameof(MessageType.Animation)), + MessageType.ForumTopicCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicCreated)), + MessageType.ForumTopicClosed => new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicClosed)), + MessageType.ForumTopicReopened => new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicReopened)), + MessageType.ForumTopicEdited => new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicEdited)), + MessageType.GeneralForumTopicHidden => new UpdateCategory(nameof(MessageType), nameof(MessageType.GeneralForumTopicHidden)), + MessageType.GeneralForumTopicUnhidden => new UpdateCategory(nameof(MessageType), nameof(MessageType.GeneralForumTopicUnhidden)), + MessageType.WriteAccessAllowed => new UpdateCategory(nameof(MessageType), nameof(MessageType.WriteAccessAllowed)), + MessageType.UsersShared => new UpdateCategory(nameof(MessageType), nameof(MessageType.UsersShared)), + MessageType.ChatShared => new UpdateCategory(nameof(MessageType), nameof(MessageType.ChatShared)), + MessageType.Story => new UpdateCategory(nameof(MessageType), nameof(MessageType.Story)), + MessageType.PassportData => new UpdateCategory(nameof(MessageType), nameof(MessageType.PassportData)), + MessageType.GiveawayCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayCreated)), + MessageType.Giveaway => new UpdateCategory(nameof(MessageType), nameof(MessageType.Giveaway)), + MessageType.GiveawayWinners => new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayWinners)), + MessageType.GiveawayCompleted => new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayCompleted)), + MessageType.BoostAdded => new UpdateCategory(nameof(MessageType), nameof(MessageType.BoostAdded)), + MessageType.ChatBackgroundSet => new UpdateCategory(nameof(MessageType), nameof(MessageType.ChatBackgroundSet)), + MessageType.PaidMedia => new UpdateCategory(nameof(MessageType), nameof(MessageType.PaidMedia)), + MessageType.RefundedPayment => new UpdateCategory(nameof(MessageType), nameof(MessageType.RefundedPayment)), + _ => new UpdateCategory(nameof(MessageType), nameof(MessageType.Unknown)) }, - UpdateType.InlineQuery => $"{typeof(UpdateType)}.{nameof(UpdateType.InlineQuery)}", - UpdateType.ChosenInlineResult => $"{typeof(UpdateType)}.{nameof(UpdateType.ChosenInlineResult)}", - UpdateType.CallbackQuery => $"{typeof(UpdateType)}.{nameof(UpdateType.CallbackQuery)}", - UpdateType.EditedMessage => $"{typeof(UpdateType)}.{nameof(UpdateType.EditedMessage)}", - UpdateType.ChannelPost => $"{typeof(UpdateType)}.{nameof(UpdateType.ChannelPost)}", - UpdateType.EditedChannelPost => $"{typeof(UpdateType)}.{nameof(UpdateType.EditedChannelPost)}", - UpdateType.ShippingQuery => $"{typeof(UpdateType)}.{nameof(UpdateType.ShippingQuery)}", - UpdateType.PreCheckoutQuery => $"{typeof(UpdateType)}.{nameof(UpdateType.PreCheckoutQuery)}", - UpdateType.Poll => $"{typeof(UpdateType)}.{nameof(UpdateType.Poll)}", - UpdateType.PollAnswer => $"{typeof(UpdateType)}.{nameof(UpdateType.PollAnswer)}", - UpdateType.MyChatMember => $"{typeof(UpdateType)}.{nameof(UpdateType.MyChatMember)}", - UpdateType.ChatMember => $"{typeof(UpdateType)}.{nameof(UpdateType.ChatMember)}", - UpdateType.ChatJoinRequest => $"{typeof(UpdateType)}.{nameof(UpdateType.ChatJoinRequest)}", - UpdateType.MessageReaction => $"{typeof(UpdateType)}.{nameof(UpdateType.MessageReaction)}", - UpdateType.MessageReactionCount => $"{typeof(UpdateType)}.{nameof(UpdateType.MessageReactionCount)}", - UpdateType.ChatBoost => $"{typeof(UpdateType)}.{nameof(UpdateType.ChatBoost)}", - UpdateType.RemovedChatBoost => $"{typeof(UpdateType)}.{nameof(UpdateType.RemovedChatBoost)}", - UpdateType.BusinessConnection => $"{typeof(UpdateType)}.{nameof(UpdateType.BusinessConnection)}", - UpdateType.BusinessMessage => $"{typeof(UpdateType)}.{nameof(UpdateType.BusinessMessage)}", - UpdateType.EditedBusinessMessage => $"{typeof(UpdateType)}.{nameof(UpdateType.EditedBusinessMessage)}", - UpdateType.DeletedBusinessMessages => $"{typeof(UpdateType)}.{nameof(UpdateType.DeletedBusinessMessages)}", - _ => $"{typeof(UpdateType)}.{nameof(UpdateType.Unknown)}" + UpdateType.InlineQuery => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.InlineQuery)), + UpdateType.ChosenInlineResult => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChosenInlineResult)), + UpdateType.CallbackQuery => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.CallbackQuery)), + UpdateType.EditedMessage => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedMessage)), + UpdateType.ChannelPost => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChannelPost)), + UpdateType.EditedChannelPost => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedChannelPost)), + UpdateType.ShippingQuery => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ShippingQuery)), + UpdateType.PreCheckoutQuery => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.PreCheckoutQuery)), + UpdateType.Poll => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Poll)), + UpdateType.PollAnswer => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.PollAnswer)), + UpdateType.MyChatMember => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MyChatMember)), + UpdateType.ChatMember => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatMember)), + UpdateType.ChatJoinRequest => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatJoinRequest)), + UpdateType.MessageReaction => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MessageReaction)), + UpdateType.MessageReactionCount => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MessageReactionCount)), + UpdateType.ChatBoost => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatBoost)), + UpdateType.RemovedChatBoost => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.RemovedChatBoost)), + UpdateType.BusinessConnection => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.BusinessConnection)), + UpdateType.BusinessMessage => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.BusinessMessage)), + UpdateType.EditedBusinessMessage => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedBusinessMessage)), + UpdateType.DeletedBusinessMessages => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.DeletedBusinessMessages)), + _ => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Unknown)) }); } } \ No newline at end of file diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index 60e3556..859aa9b 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -107,7 +107,7 @@ private async Task GetArgument(Type inputType, Update update, BotAction => update.GetUserOrDefault()!, not null when inputType == typeof(Bot) => await _serviceProvider.GetRequiredService().GetProfile(), - not null when inputType == typeof(string[]) && action.Information.ActionType == $"{typeof(MessageType)}.{nameof(MessageEntityType.BotCommand)}" + not null when inputType == typeof(string[]) && action.Information.Category.Subkind == nameof(MessageEntityType.BotCommand) => update.Message!.ExtractArguments(), not null => _serviceProvider.GetRequiredService(inputType), //TODO: this exception should never happen. diff --git a/src/Sample/Program.cs b/src/Sample/Program.cs index b86a392..b3dde37 100644 --- a/src/Sample/Program.cs +++ b/src/Sample/Program.cs @@ -1,10 +1,7 @@ -using System; -using System.Linq; -using System.Threading.Tasks; using Incremental.Common.Configuration; using Microsoft.AspNetCore.Builder; using Navigator; -using Navigator.Catalog; +using Navigator.Catalog.Factory.Extensions; using Navigator.Client; using Navigator.Configuration; using Navigator.Entities; From cefca79afecf2d623534b78ccb19c39f5df9c26a Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Mon, 19 Aug 2024 17:22:26 +0200 Subject: [PATCH 39/66] refactor: use IAsyncEnumerable for FilterActionsThatCanHandleUpdate --- src/Navigator/Strategy/NavigatorStrategy.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index 859aa9b..19930f3 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -50,17 +50,14 @@ public async Task Invoke(Update update) var relevantActions = _catalog.Retrieve(actionType); - foreach (var action in await FilterActionsThatCanHandleUpdate(relevantActions, update)) + await foreach (var action in FilterActionsThatCanHandleUpdate(relevantActions, update)) { await ExecuteAction(action, update); } } - //TODO: rework this into IAsyncEnumerable and yield - private async Task> FilterActionsThatCanHandleUpdate(IEnumerable actions, Update update) + private async IAsyncEnumerable FilterActionsThatCanHandleUpdate(IEnumerable actions, Update update) { - var successActions = new List(); - foreach (var action in actions) { var arguments = new List(); @@ -73,11 +70,9 @@ private async Task> FilterActionsThatCanHandleUpdate(IEnu if (await action.ExecuteCondition(arguments)) { - successActions.Add(action); + yield return action; } } - - return successActions; } private async Task ExecuteAction(BotAction action, Update update) From 2a6cdc10cad66c44809e45faf18dbfed34721410 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Tue, 20 Aug 2024 12:10:51 +0200 Subject: [PATCH 40/66] feat: make it work believe in your dreams --- src/Navigator/Actions/BotAction.cs | 21 +-- .../BotActionCatalogFactoryExtensions.cs | 167 +++++++++++++++++- .../ApplicationBuilderExtensions.cs | 11 +- .../EndpointRouteBuilderExtensions.cs | 17 +- src/Navigator/Strategy/NavigatorStrategy.cs | 71 ++++---- .../Telegram/TelegramUpdateExtensions.cs | 11 +- 6 files changed, 229 insertions(+), 69 deletions(-) diff --git a/src/Navigator/Actions/BotAction.cs b/src/Navigator/Actions/BotAction.cs index 976fafb..3b73153 100644 --- a/src/Navigator/Actions/BotAction.cs +++ b/src/Navigator/Actions/BotAction.cs @@ -2,10 +2,10 @@ namespace Navigator.Actions; public sealed record BotAction { - public readonly Guid Id; - public readonly BotActionInformation Information; private readonly Delegate Condition; private readonly Delegate Handler; + public readonly Guid Id; + public readonly BotActionInformation Information; public BotAction(Guid id, BotActionInformation information, Delegate condition, Delegate handler) { @@ -14,10 +14,11 @@ public BotAction(Guid id, BotActionInformation information, Delegate condition, Condition = condition; Handler = handler; } - - public async Task ExecuteCondition(params object[] args) + + public async Task ExecuteCondition(object?[] args) { - var result = Condition.DynamicInvoke(args); + // var result = Condition.DynamicInvoke(args.First()); + var result = Condition.Method.Invoke(Condition.Target, args); return result switch { @@ -26,16 +27,12 @@ public async Task ExecuteCondition(params object[] args) //TODO: specify exception _ => throw new NavigatorException() }; - } - public async Task ExecuteHandler(params object[] args) + public async Task ExecuteHandler(object?[] args) { - var result = Handler.DynamicInvoke(args); + var result = Handler.Method.Invoke(Handler.Target, args); - if (result is Task task) - { - await task; - } + if (result is Task task) await task; } } \ No newline at end of file diff --git a/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs b/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs index 3858d16..04946ba 100644 --- a/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs +++ b/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs @@ -1,6 +1,5 @@ using Navigator.Actions; using Navigator.Actions.Builder; -using Navigator.Client; using Navigator.Telegram; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -39,6 +38,27 @@ public static class BotActionCatalogFactoryExtensions // return actionBuilder; // } + /// + /// + /// Configures the bot action catalog to respond to any which includes one + /// event using the specified handler delegate. + /// + /// + /// Additionally, this method can be replaced with for more advanced configurations, + /// allowing for conditions to be defined not just by the command string but also by the content or structure + /// of the text message. This enables a wide range of customizations beyond simple command matching. + /// + /// + /// An instance of + /// The specific command string that this action should respond to. + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + /// + /// public static IBotActionBuilder OnCommand(this IBotActionCatalogFactory factory, string command, Delegate handler) { var actionBuilder = factory.OnUpdate((Update update) => update.Message?.ExtractCommand() == command, handler); @@ -47,4 +67,149 @@ public static IBotActionBuilder OnCommand(this IBotActionCatalogFactory factory, return actionBuilder; } + + /// + /// Configures the bot action catalog to respond to any event using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + /// + public static IBotActionBuilder OnMessage(this IBotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType))); + + return actionBuilder; + } + + /// + /// Configures the bot action catalog to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static IBotActionBuilder OnTextMessage(this IBotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Text))); + + return actionBuilder; + } + + /// + /// Configures the bot action catalog to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static IBotActionBuilder OnPhotoMessage(this IBotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Photo))); + + return actionBuilder; + } + + /// + /// Configures the bot action catalog to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static IBotActionBuilder OnAudioMessage(this IBotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Audio))); + + return actionBuilder; + } + + /// + /// Configures the bot action catalog to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static IBotActionBuilder OnVideoMessage(this IBotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Video))); + + return actionBuilder; + } + + /// + /// Configures the bot action catalog to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static IBotActionBuilder OnVoiceMessage(this IBotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Voice))); + + return actionBuilder; + } } \ No newline at end of file diff --git a/src/Navigator/Configuration/ApplicationBuilderExtensions.cs b/src/Navigator/Configuration/ApplicationBuilderExtensions.cs index b6976b4..a9cdd4c 100644 --- a/src/Navigator/Configuration/ApplicationBuilderExtensions.cs +++ b/src/Navigator/Configuration/ApplicationBuilderExtensions.cs @@ -1,16 +1,21 @@ using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; using Navigator.Catalog; namespace Navigator.Configuration; /// -/// Navigator extensions for +/// Navigator extensions for /// public static class ApplicationBuilderExtensions { + /// + /// Retrieves an instance of in order to build the navigator bot. + /// + /// An instance of + /// An instance of public static IBotActionCatalogFactory GetBot(this IApplicationBuilder builder) { - return new BotActionCatalogFactory(); + return builder.ApplicationServices.GetRequiredService(); } - } \ No newline at end of file diff --git a/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs b/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs index 3a18557..6947825 100644 --- a/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs +++ b/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs @@ -4,17 +4,18 @@ using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Navigator.Strategy; +using Telegram.Bot; using Telegram.Bot.Types; namespace Navigator.Configuration; /// -/// Navigator extensions for . +/// Navigator extensions for . /// public static class EndpointRouteBuilderExtensions { /// - /// Configure navigator's provider's endpoints. + /// Configure navigator's provider's endpoints. /// /// /// @@ -26,15 +27,12 @@ public static void MapNavigator(this IEndpointRouteBuilder endpointRouteBuilder) endpointRouteBuilder.MapPost(options.GetWebHookEndpointOrDefault(), ProcessTelegramUpdate); } - + private static async Task ProcessTelegramUpdate(HttpContext context) { context.Response.StatusCode = 200; - if (context.Request.ContentType != "application/json") - { - return; - } + if (context.Request.ContentType != "application/json") return; var telegramUpdate = await ParseTelegramUpdate(context.Request); @@ -42,13 +40,14 @@ private static async Task ProcessTelegramUpdate(HttpContext context) await strategy.Invoke(telegramUpdate); } - + private static async Task ParseTelegramUpdate(HttpRequest request) { try { var reader = new StreamReader(request.Body); - return JsonSerializer.Deserialize(await reader.ReadToEndAsync()) ?? throw new InvalidOperationException(); + return JsonSerializer.Deserialize(await reader.ReadToEndAsync(), JsonBotAPI.Options) ?? + throw new InvalidOperationException(); } catch (Exception e) { diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index 19930f3..f3b0722 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -12,10 +12,10 @@ namespace Navigator.Strategy; /// -/// Implements a strategy for dynamic decision-making based on incoming updates. This strategy involves classifying updates, -/// selecting relevant actions from a catalog, and executing those actions asynchronously. -/// -/// +/// Implements a strategy for dynamic decision-making based on incoming updates. This strategy involves classifying updates, +/// selecting relevant actions from a catalog, and executing those actions asynchronously. +/// +/// /// public class NavigatorStrategy : INavigatorStrategy { @@ -24,11 +24,12 @@ public class NavigatorStrategy : INavigatorStrategy private readonly IServiceProvider _serviceProvider; /// - /// Initializes a new instance of . + /// Initializes a new instance of . /// - /// An instance of . - /// An instance of . - /// An instance of . + /// An instance of . + /// An instance of . + /// An instance of + /// . public NavigatorStrategy(IBotActionCatalogFactory catalogFactory, IUpdateClassifier classifier, IServiceProvider serviceProvider) { @@ -38,69 +39,65 @@ public NavigatorStrategy(IBotActionCatalogFactory catalogFactory, IUpdateClassif } /// - /// Processes an by determining the appropriate action type, - /// retrieving relevant from the , - /// filtering those actions based on the , - /// and executing each filtered action asynchronously. + /// Processes an by determining the appropriate action type, + /// retrieving relevant from the , + /// filtering those actions based on the , + /// and executing each filtered action asynchronously. /// - /// The object to be processed. + /// The object to be processed. public async Task Invoke(Update update) { var actionType = await _classifier.Process(update); var relevantActions = _catalog.Retrieve(actionType); - await foreach (var action in FilterActionsThatCanHandleUpdate(relevantActions, update)) - { - await ExecuteAction(action, update); - } + await foreach (var action in FilterActionsThatCanHandleUpdate(relevantActions, update)) await ExecuteAction(action, update); } private async IAsyncEnumerable FilterActionsThatCanHandleUpdate(IEnumerable actions, Update update) { foreach (var action in actions) { - var arguments = new List(); + var numberOfInputs = action.Information.ConditionInputTypes.Length; + var arguments = new object?[numberOfInputs]; - foreach (var inputType in action.Information.ConditionInputTypes) + for (var i = 0; i < numberOfInputs; i++) { - var argument = await GetArgument(inputType, update, action); - arguments.Add(argument); + var inputType = action.Information.ConditionInputTypes[i]; + arguments[i] = await GetArgument(inputType, update, action); } - if (await action.ExecuteCondition(arguments)) - { - yield return action; - } + if (await action.ExecuteCondition(arguments)) yield return action; } } private async Task ExecuteAction(BotAction action, Update update) { - var arguments = new List(); + var numberOfInputs = action.Information.HandlerInputTypes.Length; + object?[] arguments = new object[numberOfInputs]; - foreach (var inputType in action.Information.HandlerInputTypes) + for (var i = 0; i < numberOfInputs; i++) { - var argument = await GetArgument(inputType, update, action); - arguments.Add(argument); + var inputType = action.Information.HandlerInputTypes[i]; + arguments[i] = await GetArgument(inputType, update, action); } await action.ExecuteHandler(arguments); } - - private async Task GetArgument(Type inputType, Update update, BotAction action) + + private async Task GetArgument(Type inputType, Update update, BotAction action) { var argument = inputType switch { not null when inputType == typeof(Update) => update, - not null when inputType == typeof(Conversation) + not null when inputType == typeof(Conversation) => update.GetConversation(), - not null when inputType == typeof(Chat) - => update.GetChatOrDefault()!, - not null when inputType == typeof(Conversation) - => update.GetUserOrDefault()!, - not null when inputType == typeof(Bot) + not null when inputType == typeof(Chat) + => update.GetConversation().Chat, + not null when inputType == typeof(Conversation) + => update.GetConversation().User, + not null when inputType == typeof(Bot) => await _serviceProvider.GetRequiredService().GetProfile(), not null when inputType == typeof(string[]) && action.Information.Category.Subkind == nameof(MessageEntityType.BotCommand) => update.Message!.ExtractArguments(), diff --git a/src/Navigator/Telegram/TelegramUpdateExtensions.cs b/src/Navigator/Telegram/TelegramUpdateExtensions.cs index 5a2930a..a54b9e1 100644 --- a/src/Navigator/Telegram/TelegramUpdateExtensions.cs +++ b/src/Navigator/Telegram/TelegramUpdateExtensions.cs @@ -14,6 +14,8 @@ internal static class TelegramUpdateExtensions var command = message.EntityValues?.First(); + command = command?[(message.Entities.First().Offset + 1)..]; + if (command?.Contains('@') == false) return command; if (botName is not null && !command?.Contains(botName) == true) return default; @@ -65,13 +67,10 @@ public static Conversation GetConversation(this Update update) var rawUser = update.GetUserOrDefault(); var rawChat = update.GetChatOrDefault(); - if (rawUser is null) - { - throw new NavigatorException("No conversation could be built, user not found."); - } + if (rawUser is null) throw new NavigatorException("No conversation could be built, user not found."); var user = rawUser.IsBot - ? new Entities.Bot(rawUser.Id, rawUser.FirstName) + ? new Bot(rawUser.Id, rawUser.FirstName) { Username = rawUser.Username!, LastName = rawUser.LastName, @@ -92,13 +91,11 @@ public static Conversation GetConversation(this Update update) var chat = default(Entities.Chat); if (rawChat is not null) - { chat = new Entities.Chat(rawChat.Id, (Entities.Chat.ChatType)rawChat.Type) { Title = rawChat.Title, IsForum = rawChat.IsForum }; - } return new Conversation(user) { From f75d22e85da591467184c3bd7df20b1f3653cd28 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Tue, 20 Aug 2024 12:11:06 +0200 Subject: [PATCH 41/66] feat: update sample --- src/Sample/Program.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Sample/Program.cs b/src/Sample/Program.cs index b3dde37..d007f7a 100644 --- a/src/Sample/Program.cs +++ b/src/Sample/Program.cs @@ -16,28 +16,27 @@ public static void Main(string[] args) var builder = WebApplication.CreateBuilder(args); builder.Configuration.AddCommonConfiguration(); - + builder.Services.AddNavigator(options => { options.SetWebHookBaseUrl(builder.Configuration["BASE_WEBHOOK_URL"]!); options.SetTelegramToken(builder.Configuration["TELEGRAM_TOKEN"]!); options.EnableTypingNotification(); }); - + var app = builder.Build(); var bot = app.GetBot(); bot.OnCommand("join", async (INavigatorClient client, Chat chat, string[] parameters) => { - var result = string.Join(' ', parameters); - + var result = string.Join(',', parameters); + await client.SendTextMessageAsync(chat, result); }); - + app.MapNavigator(); - + app.Run(); } -} - +} \ No newline at end of file From 0d2be1fc74c0ffa264f496d9701a979465643b77 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Tue, 20 Aug 2024 12:20:02 +0200 Subject: [PATCH 42/66] feat: move UpdateClassifier to its own file improve documentation --- .../Strategy/Classifier/IUpdateClassifier.cs | 104 ++--------------- .../Strategy/Classifier/UpdateClassifier.cs | 105 ++++++++++++++++++ 2 files changed, 113 insertions(+), 96 deletions(-) create mode 100644 src/Navigator/Strategy/Classifier/UpdateClassifier.cs diff --git a/src/Navigator/Strategy/Classifier/IUpdateClassifier.cs b/src/Navigator/Strategy/Classifier/IUpdateClassifier.cs index 447d602..bce4d48 100644 --- a/src/Navigator/Strategy/Classifier/IUpdateClassifier.cs +++ b/src/Navigator/Strategy/Classifier/IUpdateClassifier.cs @@ -1,105 +1,17 @@ using Navigator.Actions; using Telegram.Bot.Types; -using Telegram.Bot.Types.Enums; namespace Navigator.Strategy.Classifier; +/// +/// Defines the contract for classifying the from the Telegram Bot API. +/// public interface IUpdateClassifier { + /// + /// Processes an incoming and returns its category. + /// + /// The to process. + /// An instance of Task Process(Update update); -} - -public class UpdateClassifier : IUpdateClassifier -{ - public Task Process(Update update) - { - return Task.FromResult(update.Type switch - { - UpdateType.Unknown => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Unknown)), - UpdateType.Message when update.Message?.Entities?.First().Type == MessageEntityType.BotCommand - => new UpdateCategory(nameof(MessageType), nameof(MessageEntityType.BotCommand)), - UpdateType.Message => update.Message?.Type switch - { - MessageType.Unknown => new UpdateCategory(nameof(MessageType), nameof(MessageType.Unknown)), - MessageType.Text => new UpdateCategory(nameof(MessageType), nameof(MessageType.Text)), - MessageType.Photo => new UpdateCategory(nameof(MessageType), nameof(MessageType.Photo)), - MessageType.Audio => new UpdateCategory(nameof(MessageType), nameof(MessageType.Audio)), - MessageType.Video => new UpdateCategory(nameof(MessageType), nameof(MessageType.Video)), - MessageType.Voice => new UpdateCategory(nameof(MessageType), nameof(MessageType.Voice)), - MessageType.Document => new UpdateCategory(nameof(MessageType), nameof(MessageType.Document)), - MessageType.Sticker => new UpdateCategory(nameof(MessageType), nameof(MessageType.Sticker)), - MessageType.Location => new UpdateCategory(nameof(MessageType), nameof(MessageType.Location)), - MessageType.Contact => new UpdateCategory(nameof(MessageType), nameof(MessageType.Contact)), - MessageType.Venue => new UpdateCategory(nameof(MessageType), nameof(MessageType.Venue)), - MessageType.Game => new UpdateCategory(nameof(MessageType), nameof(MessageType.Game)), - MessageType.VideoNote => new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoNote)), - MessageType.Invoice => new UpdateCategory(nameof(MessageType), nameof(MessageType.Invoice)), - MessageType.SuccessfulPayment => new UpdateCategory(nameof(MessageType), nameof(MessageType.SuccessfulPayment)), - MessageType.ConnectedWebsite => new UpdateCategory(nameof(MessageType), nameof(MessageType.ConnectedWebsite)), - MessageType.NewChatMembers => new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatMembers)), - MessageType.LeftChatMember => new UpdateCategory(nameof(MessageType), nameof(MessageType.LeftChatMember)), - MessageType.NewChatTitle => new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatTitle)), - MessageType.NewChatPhoto => new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatPhoto)), - MessageType.PinnedMessage => new UpdateCategory(nameof(MessageType), nameof(MessageType.PinnedMessage)), - MessageType.DeleteChatPhoto => new UpdateCategory(nameof(MessageType), nameof(MessageType.DeleteChatPhoto)), - MessageType.GroupChatCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.GroupChatCreated)), - MessageType.SupergroupChatCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.SupergroupChatCreated)), - MessageType.ChannelChatCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.ChannelChatCreated)), - MessageType.MigrateFromChatId => new UpdateCategory(nameof(MessageType), nameof(MessageType.MigrateFromChatId)), - MessageType.MigrateToChatId => new UpdateCategory(nameof(MessageType), nameof(MessageType.MigrateToChatId)), - MessageType.Poll => new UpdateCategory(nameof(MessageType), nameof(MessageType.Poll)), - MessageType.Dice => new UpdateCategory(nameof(MessageType), nameof(MessageType.Dice)), - MessageType.MessageAutoDeleteTimerChanged => new UpdateCategory(nameof(MessageType), nameof(MessageType.MessageAutoDeleteTimerChanged)), - MessageType.ProximityAlertTriggered => new UpdateCategory(nameof(MessageType), nameof(MessageType.ProximityAlertTriggered)), - MessageType.WebAppData => new UpdateCategory(nameof(MessageType), nameof(MessageType.WebAppData)), - MessageType.VideoChatScheduled => new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatScheduled)), - MessageType.VideoChatStarted => new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatStarted)), - MessageType.VideoChatEnded => new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatEnded)), - MessageType.VideoChatParticipantsInvited => new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatParticipantsInvited)), - MessageType.Animation => new UpdateCategory(nameof(MessageType), nameof(MessageType.Animation)), - MessageType.ForumTopicCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicCreated)), - MessageType.ForumTopicClosed => new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicClosed)), - MessageType.ForumTopicReopened => new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicReopened)), - MessageType.ForumTopicEdited => new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicEdited)), - MessageType.GeneralForumTopicHidden => new UpdateCategory(nameof(MessageType), nameof(MessageType.GeneralForumTopicHidden)), - MessageType.GeneralForumTopicUnhidden => new UpdateCategory(nameof(MessageType), nameof(MessageType.GeneralForumTopicUnhidden)), - MessageType.WriteAccessAllowed => new UpdateCategory(nameof(MessageType), nameof(MessageType.WriteAccessAllowed)), - MessageType.UsersShared => new UpdateCategory(nameof(MessageType), nameof(MessageType.UsersShared)), - MessageType.ChatShared => new UpdateCategory(nameof(MessageType), nameof(MessageType.ChatShared)), - MessageType.Story => new UpdateCategory(nameof(MessageType), nameof(MessageType.Story)), - MessageType.PassportData => new UpdateCategory(nameof(MessageType), nameof(MessageType.PassportData)), - MessageType.GiveawayCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayCreated)), - MessageType.Giveaway => new UpdateCategory(nameof(MessageType), nameof(MessageType.Giveaway)), - MessageType.GiveawayWinners => new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayWinners)), - MessageType.GiveawayCompleted => new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayCompleted)), - MessageType.BoostAdded => new UpdateCategory(nameof(MessageType), nameof(MessageType.BoostAdded)), - MessageType.ChatBackgroundSet => new UpdateCategory(nameof(MessageType), nameof(MessageType.ChatBackgroundSet)), - MessageType.PaidMedia => new UpdateCategory(nameof(MessageType), nameof(MessageType.PaidMedia)), - MessageType.RefundedPayment => new UpdateCategory(nameof(MessageType), nameof(MessageType.RefundedPayment)), - _ => new UpdateCategory(nameof(MessageType), nameof(MessageType.Unknown)) - }, - UpdateType.InlineQuery => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.InlineQuery)), - UpdateType.ChosenInlineResult => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChosenInlineResult)), - UpdateType.CallbackQuery => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.CallbackQuery)), - UpdateType.EditedMessage => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedMessage)), - UpdateType.ChannelPost => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChannelPost)), - UpdateType.EditedChannelPost => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedChannelPost)), - UpdateType.ShippingQuery => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ShippingQuery)), - UpdateType.PreCheckoutQuery => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.PreCheckoutQuery)), - UpdateType.Poll => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Poll)), - UpdateType.PollAnswer => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.PollAnswer)), - UpdateType.MyChatMember => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MyChatMember)), - UpdateType.ChatMember => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatMember)), - UpdateType.ChatJoinRequest => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatJoinRequest)), - UpdateType.MessageReaction => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MessageReaction)), - UpdateType.MessageReactionCount => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MessageReactionCount)), - UpdateType.ChatBoost => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatBoost)), - UpdateType.RemovedChatBoost => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.RemovedChatBoost)), - UpdateType.BusinessConnection => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.BusinessConnection)), - UpdateType.BusinessMessage => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.BusinessMessage)), - UpdateType.EditedBusinessMessage => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedBusinessMessage)), - UpdateType.DeletedBusinessMessages => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.DeletedBusinessMessages)), - _ => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Unknown)) - }); - } } \ No newline at end of file diff --git a/src/Navigator/Strategy/Classifier/UpdateClassifier.cs b/src/Navigator/Strategy/Classifier/UpdateClassifier.cs new file mode 100644 index 0000000..01ee1e7 --- /dev/null +++ b/src/Navigator/Strategy/Classifier/UpdateClassifier.cs @@ -0,0 +1,105 @@ +using Navigator.Actions; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; + +namespace Navigator.Strategy.Classifier; + +/// +public class UpdateClassifier : IUpdateClassifier +{ + /// + public Task Process(Update update) + { + return Task.FromResult(update.Type switch + { + UpdateType.Unknown => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Unknown)), + UpdateType.Message when update.Message?.Entities?.First().Type == MessageEntityType.BotCommand + => new UpdateCategory(nameof(MessageType), nameof(MessageEntityType.BotCommand)), + UpdateType.Message => update.Message?.Type switch + { + MessageType.Unknown => new UpdateCategory(nameof(MessageType), nameof(MessageType.Unknown)), + MessageType.Text => new UpdateCategory(nameof(MessageType), nameof(MessageType.Text)), + MessageType.Photo => new UpdateCategory(nameof(MessageType), nameof(MessageType.Photo)), + MessageType.Audio => new UpdateCategory(nameof(MessageType), nameof(MessageType.Audio)), + MessageType.Video => new UpdateCategory(nameof(MessageType), nameof(MessageType.Video)), + MessageType.Voice => new UpdateCategory(nameof(MessageType), nameof(MessageType.Voice)), + MessageType.Document => new UpdateCategory(nameof(MessageType), nameof(MessageType.Document)), + MessageType.Sticker => new UpdateCategory(nameof(MessageType), nameof(MessageType.Sticker)), + MessageType.Location => new UpdateCategory(nameof(MessageType), nameof(MessageType.Location)), + MessageType.Contact => new UpdateCategory(nameof(MessageType), nameof(MessageType.Contact)), + MessageType.Venue => new UpdateCategory(nameof(MessageType), nameof(MessageType.Venue)), + MessageType.Game => new UpdateCategory(nameof(MessageType), nameof(MessageType.Game)), + MessageType.VideoNote => new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoNote)), + MessageType.Invoice => new UpdateCategory(nameof(MessageType), nameof(MessageType.Invoice)), + MessageType.SuccessfulPayment => new UpdateCategory(nameof(MessageType), nameof(MessageType.SuccessfulPayment)), + MessageType.ConnectedWebsite => new UpdateCategory(nameof(MessageType), nameof(MessageType.ConnectedWebsite)), + MessageType.NewChatMembers => new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatMembers)), + MessageType.LeftChatMember => new UpdateCategory(nameof(MessageType), nameof(MessageType.LeftChatMember)), + MessageType.NewChatTitle => new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatTitle)), + MessageType.NewChatPhoto => new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatPhoto)), + MessageType.PinnedMessage => new UpdateCategory(nameof(MessageType), nameof(MessageType.PinnedMessage)), + MessageType.DeleteChatPhoto => new UpdateCategory(nameof(MessageType), nameof(MessageType.DeleteChatPhoto)), + MessageType.GroupChatCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.GroupChatCreated)), + MessageType.SupergroupChatCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.SupergroupChatCreated)), + MessageType.ChannelChatCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.ChannelChatCreated)), + MessageType.MigrateFromChatId => new UpdateCategory(nameof(MessageType), nameof(MessageType.MigrateFromChatId)), + MessageType.MigrateToChatId => new UpdateCategory(nameof(MessageType), nameof(MessageType.MigrateToChatId)), + MessageType.Poll => new UpdateCategory(nameof(MessageType), nameof(MessageType.Poll)), + MessageType.Dice => new UpdateCategory(nameof(MessageType), nameof(MessageType.Dice)), + MessageType.MessageAutoDeleteTimerChanged => new UpdateCategory(nameof(MessageType), + nameof(MessageType.MessageAutoDeleteTimerChanged)), + MessageType.ProximityAlertTriggered => new UpdateCategory(nameof(MessageType), nameof(MessageType.ProximityAlertTriggered)), + MessageType.WebAppData => new UpdateCategory(nameof(MessageType), nameof(MessageType.WebAppData)), + MessageType.VideoChatScheduled => new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatScheduled)), + MessageType.VideoChatStarted => new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatStarted)), + MessageType.VideoChatEnded => new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatEnded)), + MessageType.VideoChatParticipantsInvited => new UpdateCategory(nameof(MessageType), + nameof(MessageType.VideoChatParticipantsInvited)), + MessageType.Animation => new UpdateCategory(nameof(MessageType), nameof(MessageType.Animation)), + MessageType.ForumTopicCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicCreated)), + MessageType.ForumTopicClosed => new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicClosed)), + MessageType.ForumTopicReopened => new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicReopened)), + MessageType.ForumTopicEdited => new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicEdited)), + MessageType.GeneralForumTopicHidden => new UpdateCategory(nameof(MessageType), nameof(MessageType.GeneralForumTopicHidden)), + MessageType.GeneralForumTopicUnhidden => new UpdateCategory(nameof(MessageType), + nameof(MessageType.GeneralForumTopicUnhidden)), + MessageType.WriteAccessAllowed => new UpdateCategory(nameof(MessageType), nameof(MessageType.WriteAccessAllowed)), + MessageType.UsersShared => new UpdateCategory(nameof(MessageType), nameof(MessageType.UsersShared)), + MessageType.ChatShared => new UpdateCategory(nameof(MessageType), nameof(MessageType.ChatShared)), + MessageType.Story => new UpdateCategory(nameof(MessageType), nameof(MessageType.Story)), + MessageType.PassportData => new UpdateCategory(nameof(MessageType), nameof(MessageType.PassportData)), + MessageType.GiveawayCreated => new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayCreated)), + MessageType.Giveaway => new UpdateCategory(nameof(MessageType), nameof(MessageType.Giveaway)), + MessageType.GiveawayWinners => new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayWinners)), + MessageType.GiveawayCompleted => new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayCompleted)), + MessageType.BoostAdded => new UpdateCategory(nameof(MessageType), nameof(MessageType.BoostAdded)), + MessageType.ChatBackgroundSet => new UpdateCategory(nameof(MessageType), nameof(MessageType.ChatBackgroundSet)), + MessageType.PaidMedia => new UpdateCategory(nameof(MessageType), nameof(MessageType.PaidMedia)), + MessageType.RefundedPayment => new UpdateCategory(nameof(MessageType), nameof(MessageType.RefundedPayment)), + _ => new UpdateCategory(nameof(MessageType), nameof(MessageType.Unknown)) + }, + UpdateType.InlineQuery => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.InlineQuery)), + UpdateType.ChosenInlineResult => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChosenInlineResult)), + UpdateType.CallbackQuery => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.CallbackQuery)), + UpdateType.EditedMessage => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedMessage)), + UpdateType.ChannelPost => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChannelPost)), + UpdateType.EditedChannelPost => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedChannelPost)), + UpdateType.ShippingQuery => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ShippingQuery)), + UpdateType.PreCheckoutQuery => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.PreCheckoutQuery)), + UpdateType.Poll => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Poll)), + UpdateType.PollAnswer => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.PollAnswer)), + UpdateType.MyChatMember => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MyChatMember)), + UpdateType.ChatMember => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatMember)), + UpdateType.ChatJoinRequest => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatJoinRequest)), + UpdateType.MessageReaction => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MessageReaction)), + UpdateType.MessageReactionCount => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MessageReactionCount)), + UpdateType.ChatBoost => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatBoost)), + UpdateType.RemovedChatBoost => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.RemovedChatBoost)), + UpdateType.BusinessConnection => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.BusinessConnection)), + UpdateType.BusinessMessage => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.BusinessMessage)), + UpdateType.EditedBusinessMessage => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedBusinessMessage)), + UpdateType.DeletedBusinessMessages => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.DeletedBusinessMessages)), + _ => new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Unknown)) + }); + } +} \ No newline at end of file From 3c7d219535338df8333f20b8cf2e50d88e2ec34f Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Tue, 20 Aug 2024 12:20:31 +0200 Subject: [PATCH 43/66] chore: adjust namespaces in Navigator project --- src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs | 3 +-- src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs | 2 +- src/Navigator/Client/NavigatorClient.cs | 1 + src/Navigator/Configuration/ApplicationBuilderExtensions.cs | 1 + src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs | 1 + src/Navigator/Configuration/NavigatorConfiguration.cs | 1 + src/Navigator/Configuration/Options/INavigatorOptions.cs | 2 +- src/Navigator/Configuration/Options/NavigatorOptions.cs | 2 +- .../Options/NavigatorOptionsCollectionExtensions.cs | 3 +-- src/Navigator/Hosted/SetTelegramBotWebHookHostedService.cs | 1 + src/Navigator/ServiceCollectionExtensions.cs | 2 ++ src/Navigator/Strategy/NavigatorStrategy.cs | 1 + src/Sample/Program.cs | 1 + 13 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs b/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs index a2081c7..a11afb8 100644 --- a/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs +++ b/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs @@ -1,9 +1,8 @@ -using System.Collections.ObjectModel; using Navigator.Actions; using Navigator.Actions.Builder; using Telegram.Bot.Types.Enums; -namespace Navigator.Catalog; +namespace Navigator.Catalog.Factory; public class BotActionCatalogFactory : IBotActionCatalogFactory { diff --git a/src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs b/src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs index c9f2028..bd7721a 100644 --- a/src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs +++ b/src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs @@ -1,6 +1,6 @@ using Navigator.Actions.Builder; -namespace Navigator.Catalog; +namespace Navigator.Catalog.Factory; public interface IBotActionCatalogFactory { diff --git a/src/Navigator/Client/NavigatorClient.cs b/src/Navigator/Client/NavigatorClient.cs index 0e40063..e89500c 100644 --- a/src/Navigator/Client/NavigatorClient.cs +++ b/src/Navigator/Client/NavigatorClient.cs @@ -1,4 +1,5 @@ using Navigator.Configuration; +using Navigator.Configuration.Options; using Navigator.Entities; using Telegram.Bot; diff --git a/src/Navigator/Configuration/ApplicationBuilderExtensions.cs b/src/Navigator/Configuration/ApplicationBuilderExtensions.cs index a9cdd4c..29f4896 100644 --- a/src/Navigator/Configuration/ApplicationBuilderExtensions.cs +++ b/src/Navigator/Configuration/ApplicationBuilderExtensions.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Navigator.Catalog; +using Navigator.Catalog.Factory; namespace Navigator.Configuration; diff --git a/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs b/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs index 6947825..7953d93 100644 --- a/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs +++ b/src/Navigator/Configuration/EndpointRouteBuilderExtensions.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; +using Navigator.Configuration.Options; using Navigator.Strategy; using Telegram.Bot; using Telegram.Bot.Types; diff --git a/src/Navigator/Configuration/NavigatorConfiguration.cs b/src/Navigator/Configuration/NavigatorConfiguration.cs index 84ca0be..a4c48e2 100644 --- a/src/Navigator/Configuration/NavigatorConfiguration.cs +++ b/src/Navigator/Configuration/NavigatorConfiguration.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Navigator.Configuration.Options; namespace Navigator.Configuration; diff --git a/src/Navigator/Configuration/Options/INavigatorOptions.cs b/src/Navigator/Configuration/Options/INavigatorOptions.cs index b7f9362..ec4ec22 100644 --- a/src/Navigator/Configuration/Options/INavigatorOptions.cs +++ b/src/Navigator/Configuration/Options/INavigatorOptions.cs @@ -1,4 +1,4 @@ -namespace Navigator.Configuration; +namespace Navigator.Configuration.Options; /// /// Represents all the options you can use to configure Navigator. diff --git a/src/Navigator/Configuration/Options/NavigatorOptions.cs b/src/Navigator/Configuration/Options/NavigatorOptions.cs index 999fb29..5fa6553 100644 --- a/src/Navigator/Configuration/Options/NavigatorOptions.cs +++ b/src/Navigator/Configuration/Options/NavigatorOptions.cs @@ -1,4 +1,4 @@ -namespace Navigator.Configuration; +namespace Navigator.Configuration.Options; /// public class NavigatorOptions : INavigatorOptions diff --git a/src/Navigator/Configuration/Options/NavigatorOptionsCollectionExtensions.cs b/src/Navigator/Configuration/Options/NavigatorOptionsCollectionExtensions.cs index 974443f..3999c91 100644 --- a/src/Navigator/Configuration/Options/NavigatorOptionsCollectionExtensions.cs +++ b/src/Navigator/Configuration/Options/NavigatorOptionsCollectionExtensions.cs @@ -1,8 +1,7 @@ -using System.Reflection; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; -namespace Navigator.Configuration; +namespace Navigator.Configuration.Options; /// /// Navigator Configuration Options. diff --git a/src/Navigator/Hosted/SetTelegramBotWebHookHostedService.cs b/src/Navigator/Hosted/SetTelegramBotWebHookHostedService.cs index 3dd4619..5b3ae42 100644 --- a/src/Navigator/Hosted/SetTelegramBotWebHookHostedService.cs +++ b/src/Navigator/Hosted/SetTelegramBotWebHookHostedService.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging; using Navigator.Client; using Navigator.Configuration; +using Navigator.Configuration.Options; using Telegram.Bot; namespace Navigator.Hosted; diff --git a/src/Navigator/ServiceCollectionExtensions.cs b/src/Navigator/ServiceCollectionExtensions.cs index 81b3a70..41e5c5d 100644 --- a/src/Navigator/ServiceCollectionExtensions.cs +++ b/src/Navigator/ServiceCollectionExtensions.cs @@ -1,7 +1,9 @@ using Microsoft.Extensions.DependencyInjection; using Navigator.Catalog; +using Navigator.Catalog.Factory; using Navigator.Client; using Navigator.Configuration; +using Navigator.Configuration.Options; using Navigator.Hosted; using Navigator.Strategy; using Navigator.Strategy.Classifier; diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index f3b0722..a010710 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Navigator.Actions; using Navigator.Catalog; +using Navigator.Catalog.Factory; using Navigator.Client; using Navigator.Entities; using Navigator.Strategy.Classifier; diff --git a/src/Sample/Program.cs b/src/Sample/Program.cs index d007f7a..70d0645 100644 --- a/src/Sample/Program.cs +++ b/src/Sample/Program.cs @@ -4,6 +4,7 @@ using Navigator.Catalog.Factory.Extensions; using Navigator.Client; using Navigator.Configuration; +using Navigator.Configuration.Options; using Navigator.Entities; using Telegram.Bot; From 29fbfc9376d078257970f42cad1f5a1ee4d28090 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Tue, 20 Aug 2024 13:07:52 +0200 Subject: [PATCH 44/66] refactor: simplify class vs interface on some cases --- .../Actions/Builder/BotActionBuilder.cs | 51 ++++++++++--------- .../Actions/Builder/IBotActionBuilder.cs | 9 ---- .../Factory/BotActionCatalogFactory.cs | 11 ++-- .../BotActionCatalogFactoryExtensions.cs | 42 +++++++-------- .../Factory/IBotActionCatalogFactory.cs | 10 ---- .../ApplicationBuilderExtensions.cs | 9 ++-- src/Navigator/ServiceCollectionExtensions.cs | 12 ++--- src/Navigator/Strategy/NavigatorStrategy.cs | 4 +- 8 files changed, 61 insertions(+), 87 deletions(-) delete mode 100644 src/Navigator/Actions/Builder/IBotActionBuilder.cs delete mode 100644 src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs diff --git a/src/Navigator/Actions/Builder/BotActionBuilder.cs b/src/Navigator/Actions/Builder/BotActionBuilder.cs index 283ec05..d3ccbc6 100644 --- a/src/Navigator/Actions/Builder/BotActionBuilder.cs +++ b/src/Navigator/Actions/Builder/BotActionBuilder.cs @@ -1,18 +1,35 @@ -using Telegram.Bot.Types.Enums; - namespace Navigator.Actions.Builder; -public class BotActionBuilder : IBotActionBuilder +public class BotActionBuilder { - private readonly Guid _id; private readonly Delegate _condition; - private readonly Delegate _handler; private readonly Type[] _conditionInputTypes; + private readonly Delegate _handler; private readonly Type[] _handlerInputTypes; + private readonly Guid _id; + + public BotActionBuilder(Delegate condition, Delegate handler) + { + _id = Guid.NewGuid(); + + if (!(condition.Method.ReturnType != typeof(Task) || condition.Method.ReturnType != typeof(bool))) + throw new NavigatorException("The condition delegate must return Task or bool"); + + _condition = condition; + _conditionInputTypes = condition.Method.GetParameters().Select(info => info.ParameterType).ToArray(); + _handler = handler; + _handlerInputTypes = handler.Method.GetParameters().Select(info => info.ParameterType).ToArray(); + _priority = Priority.Default; + } + private UpdateCategory _category { get; set; } private ushort _priority { get; set; } - private TimeSpan? _cooldown { get; set; } + private TimeSpan? _cooldown { get; set; } + /// + /// Builds the bot action. + /// + /// An instance of public BotAction Build() { var information = new BotActionInformation @@ -26,36 +43,20 @@ public BotAction Build() return new BotAction(_id, information, _condition, _handler); } - - public BotActionBuilder(Delegate condition, Delegate handler) - { - _id = Guid.NewGuid(); - if (!(condition.Method.ReturnType != typeof(Task) || condition.Method.ReturnType != typeof(bool))) - { - throw new NavigatorException("The condition delegate must return Task or bool"); - } - - _condition = condition; - _conditionInputTypes = condition.Method.GetParameters().Select(info => info.ParameterType).ToArray(); - _handler = handler; - _handlerInputTypes = handler.Method.GetParameters().Select(info => info.ParameterType).ToArray(); - _priority = Priority.Default; - } - - public IBotActionBuilder WithPriority(ushort priority) + public BotActionBuilder WithPriority(ushort priority) { _priority = priority; return this; } - public IBotActionBuilder WithCooldown(TimeSpan cooldown) + public BotActionBuilder WithCooldown(TimeSpan cooldown) { _cooldown = cooldown; return this; } - public IBotActionBuilder SetType(UpdateCategory category) + public BotActionBuilder SetType(UpdateCategory category) { _category = category; return this; diff --git a/src/Navigator/Actions/Builder/IBotActionBuilder.cs b/src/Navigator/Actions/Builder/IBotActionBuilder.cs deleted file mode 100644 index b53999b..0000000 --- a/src/Navigator/Actions/Builder/IBotActionBuilder.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Navigator.Actions.Builder; - -public interface IBotActionBuilder -{ - public BotAction Build(); - public IBotActionBuilder WithPriority(ushort priority); - public IBotActionBuilder WithCooldown(TimeSpan cooldown); - public IBotActionBuilder SetType(UpdateCategory category); -} \ No newline at end of file diff --git a/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs b/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs index a11afb8..e03b092 100644 --- a/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs +++ b/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs @@ -4,18 +4,18 @@ namespace Navigator.Catalog.Factory; -public class BotActionCatalogFactory : IBotActionCatalogFactory +public class BotActionCatalogFactory { private List Actions { get; } = []; private BotActionCatalog? Catalog { get; set; } - public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler) + public BotActionBuilder OnUpdate(Delegate condition, Delegate handler) { var id = Guid.NewGuid(); var actionBuilder = new BotActionBuilder(condition, handler); actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Unknown))); - + Actions.Add(actionBuilder); return actionBuilder; @@ -23,10 +23,7 @@ public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler) public BotActionCatalog Retrieve() { - if (Catalog is null) - { - Build(); - } + if (Catalog is null) Build(); return Catalog!; } diff --git a/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs b/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs index 04946ba..e753997 100644 --- a/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs +++ b/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs @@ -49,17 +49,17 @@ public static class BotActionCatalogFactoryExtensions /// of the text message. This enables a wide range of customizations beyond simple command matching. /// /// - /// An instance of + /// An instance of /// The specific command string that this action should respond to. /// /// A delegate representing the action to take when the condition is met. /// /// - /// A configured instance of that allows further customization of the bot action. + /// A configured instance of that allows further customization of the bot action. /// /// /// - public static IBotActionBuilder OnCommand(this IBotActionCatalogFactory factory, string command, Delegate handler) + public static BotActionBuilder OnCommand(this BotActionCatalogFactory factory, string command, Delegate handler) { var actionBuilder = factory.OnUpdate((Update update) => update.Message?.ExtractCommand() == command, handler); @@ -72,7 +72,7 @@ public static IBotActionBuilder OnCommand(this IBotActionCatalogFactory factory, /// Configures the bot action catalog to respond to any event using the specified condition and handler /// delegates. /// - /// An instance of + /// An instance of /// /// A delegate representing the condition under which the handler should be invoked. /// Must return or where TResult is @@ -81,10 +81,10 @@ public static IBotActionBuilder OnCommand(this IBotActionCatalogFactory factory, /// A delegate representing the action to take when the condition is met. /// /// - /// A configured instance of that allows further customization of the bot action. + /// A configured instance of that allows further customization of the bot action. /// /// - public static IBotActionBuilder OnMessage(this IBotActionCatalogFactory factory, Delegate condition, Delegate handler) + public static BotActionBuilder OnMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) { var actionBuilder = factory.OnUpdate(condition, handler); @@ -97,7 +97,7 @@ public static IBotActionBuilder OnMessage(this IBotActionCatalogFactory factory, /// Configures the bot action catalog to respond to events using the specified condition and handler /// delegates. /// - /// An instance of + /// An instance of /// /// A delegate representing the condition under which the handler should be invoked. /// Must return or where TResult is @@ -106,9 +106,9 @@ public static IBotActionBuilder OnMessage(this IBotActionCatalogFactory factory, /// A delegate representing the action to take when the condition is met. /// /// - /// A configured instance of that allows further customization of the bot action. + /// A configured instance of that allows further customization of the bot action. /// - public static IBotActionBuilder OnTextMessage(this IBotActionCatalogFactory factory, Delegate condition, Delegate handler) + public static BotActionBuilder OnTextMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) { var actionBuilder = factory.OnUpdate(condition, handler); @@ -121,7 +121,7 @@ public static IBotActionBuilder OnTextMessage(this IBotActionCatalogFactory fact /// Configures the bot action catalog to respond to events using the specified condition and handler /// delegates. /// - /// An instance of + /// An instance of /// /// A delegate representing the condition under which the handler should be invoked. /// Must return or where TResult is @@ -130,9 +130,9 @@ public static IBotActionBuilder OnTextMessage(this IBotActionCatalogFactory fact /// A delegate representing the action to take when the condition is met. /// /// - /// A configured instance of that allows further customization of the bot action. + /// A configured instance of that allows further customization of the bot action. /// - public static IBotActionBuilder OnPhotoMessage(this IBotActionCatalogFactory factory, Delegate condition, Delegate handler) + public static BotActionBuilder OnPhotoMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) { var actionBuilder = factory.OnUpdate(condition, handler); @@ -145,7 +145,7 @@ public static IBotActionBuilder OnPhotoMessage(this IBotActionCatalogFactory fac /// Configures the bot action catalog to respond to events using the specified condition and handler /// delegates. /// - /// An instance of + /// An instance of /// /// A delegate representing the condition under which the handler should be invoked. /// Must return or where TResult is @@ -154,9 +154,9 @@ public static IBotActionBuilder OnPhotoMessage(this IBotActionCatalogFactory fac /// A delegate representing the action to take when the condition is met. /// /// - /// A configured instance of that allows further customization of the bot action. + /// A configured instance of that allows further customization of the bot action. /// - public static IBotActionBuilder OnAudioMessage(this IBotActionCatalogFactory factory, Delegate condition, Delegate handler) + public static BotActionBuilder OnAudioMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) { var actionBuilder = factory.OnUpdate(condition, handler); @@ -169,7 +169,7 @@ public static IBotActionBuilder OnAudioMessage(this IBotActionCatalogFactory fac /// Configures the bot action catalog to respond to events using the specified condition and handler /// delegates. /// - /// An instance of + /// An instance of /// /// A delegate representing the condition under which the handler should be invoked. /// Must return or where TResult is @@ -178,9 +178,9 @@ public static IBotActionBuilder OnAudioMessage(this IBotActionCatalogFactory fac /// A delegate representing the action to take when the condition is met. /// /// - /// A configured instance of that allows further customization of the bot action. + /// A configured instance of that allows further customization of the bot action. /// - public static IBotActionBuilder OnVideoMessage(this IBotActionCatalogFactory factory, Delegate condition, Delegate handler) + public static BotActionBuilder OnVideoMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) { var actionBuilder = factory.OnUpdate(condition, handler); @@ -193,7 +193,7 @@ public static IBotActionBuilder OnVideoMessage(this IBotActionCatalogFactory fac /// Configures the bot action catalog to respond to events using the specified condition and handler /// delegates. /// - /// An instance of + /// An instance of /// /// A delegate representing the condition under which the handler should be invoked. /// Must return or where TResult is @@ -202,9 +202,9 @@ public static IBotActionBuilder OnVideoMessage(this IBotActionCatalogFactory fac /// A delegate representing the action to take when the condition is met. /// /// - /// A configured instance of that allows further customization of the bot action. + /// A configured instance of that allows further customization of the bot action. /// - public static IBotActionBuilder OnVoiceMessage(this IBotActionCatalogFactory factory, Delegate condition, Delegate handler) + public static BotActionBuilder OnVoiceMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) { var actionBuilder = factory.OnUpdate(condition, handler); diff --git a/src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs b/src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs deleted file mode 100644 index bd7721a..0000000 --- a/src/Navigator/Catalog/Factory/IBotActionCatalogFactory.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Navigator.Actions.Builder; - -namespace Navigator.Catalog.Factory; - -public interface IBotActionCatalogFactory -{ - public IBotActionBuilder OnUpdate(Delegate condition, Delegate handler); - - public BotActionCatalog Retrieve(); -} \ No newline at end of file diff --git a/src/Navigator/Configuration/ApplicationBuilderExtensions.cs b/src/Navigator/Configuration/ApplicationBuilderExtensions.cs index 29f4896..12c96dc 100644 --- a/src/Navigator/Configuration/ApplicationBuilderExtensions.cs +++ b/src/Navigator/Configuration/ApplicationBuilderExtensions.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; -using Navigator.Catalog; using Navigator.Catalog.Factory; namespace Navigator.Configuration; @@ -11,12 +10,12 @@ namespace Navigator.Configuration; public static class ApplicationBuilderExtensions { /// - /// Retrieves an instance of in order to build the navigator bot. + /// Retrieves an instance of in order to build the navigator bot. /// /// An instance of - /// An instance of - public static IBotActionCatalogFactory GetBot(this IApplicationBuilder builder) + /// An instance of + public static BotActionCatalogFactory GetBot(this IApplicationBuilder builder) { - return builder.ApplicationServices.GetRequiredService(); + return builder.ApplicationServices.GetRequiredService(); } } \ No newline at end of file diff --git a/src/Navigator/ServiceCollectionExtensions.cs b/src/Navigator/ServiceCollectionExtensions.cs index 41e5c5d..2bc8e6f 100644 --- a/src/Navigator/ServiceCollectionExtensions.cs +++ b/src/Navigator/ServiceCollectionExtensions.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.DependencyInjection; -using Navigator.Catalog; using Navigator.Catalog.Factory; using Navigator.Client; using Navigator.Configuration; @@ -7,17 +6,16 @@ using Navigator.Hosted; using Navigator.Strategy; using Navigator.Strategy.Classifier; -using Scrutor; namespace Navigator; /// -/// Extensions for configuring Navigator. +/// Extensions for configuring Navigator. /// public static class ServiceCollectionExtensions { /// - /// Adds Navigator. + /// Adds Navigator. /// /// /// @@ -26,19 +24,17 @@ public static class ServiceCollectionExtensions public static NavigatorConfiguration AddNavigator(this IServiceCollection services, Action options) { if (options == null) - { throw new ArgumentNullException(nameof(options), "Navigator options are required for navigator framework to work."); - } var navigatorBuilder = new NavigatorConfiguration(options, services); services.AddScoped(); - services.AddSingleton(); + services.AddSingleton(); services.AddScoped(); services.AddScoped(); - + services.AddHostedService(); navigatorBuilder.RegisterOrReplaceOptions(); diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index a010710..b91cbb2 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -27,11 +27,11 @@ public class NavigatorStrategy : INavigatorStrategy /// /// Initializes a new instance of . /// - /// An instance of . + /// An instance of . /// An instance of . /// An instance of /// . - public NavigatorStrategy(IBotActionCatalogFactory catalogFactory, IUpdateClassifier classifier, + public NavigatorStrategy(BotActionCatalogFactory catalogFactory, IUpdateClassifier classifier, IServiceProvider serviceProvider) { _catalog = catalogFactory.Retrieve(); From 3613ff5313f3630932ab93a6bb68d5606e7c59bf Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Tue, 20 Aug 2024 14:42:36 +0200 Subject: [PATCH 45/66] feat: add extensions for all types of messages and updates --- .../BotActionCatalogFactoryExtensions.cs | 1741 ++++++++++++++++- 1 file changed, 1726 insertions(+), 15 deletions(-) diff --git a/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs b/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs index e753997..207669e 100644 --- a/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs +++ b/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs @@ -3,9 +3,17 @@ using Navigator.Telegram; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; +using Telegram.Bot.Types.Passport; +using Telegram.Bot.Types.Payments; namespace Navigator.Catalog.Factory.Extensions; +/// +/// These extensions provide a convenient way to create bot actions to respond to different types of updates. +/// Each extension method takes a condition and handler delegate for the bot action. The condition is a delegate that determines whether +/// the bot action should be invoked for the given update, and the handler is a delegate that defines what the bot action should do when +/// the condition is met. +/// public static class BotActionCatalogFactoryExtensions { // public static IBotActionBuilder OnUpdate(this IBotActionCatalogFactory factory, Func> condition, Delegate handler) @@ -40,12 +48,12 @@ public static class BotActionCatalogFactoryExtensions /// /// - /// Configures the bot action catalog to respond to any which includes one + /// Configures a new bot action to respond to any which includes one /// event using the specified handler delegate. /// /// - /// Additionally, this method can be replaced with for more advanced configurations, - /// allowing for conditions to be defined not just by the command string but also by the content or structure + /// Additionally, this method can be replaced with or for more advanced + /// configurations, allowing for conditions to be defined not just by the command string but also by the content or structure /// of the text message. This enables a wide range of customizations beyond simple command matching. /// /// @@ -57,7 +65,7 @@ public static class BotActionCatalogFactoryExtensions /// /// A configured instance of that allows further customization of the bot action. /// - /// + /// /// public static BotActionBuilder OnCommand(this BotActionCatalogFactory factory, string command, Delegate handler) { @@ -69,7 +77,7 @@ public static BotActionBuilder OnCommand(this BotActionCatalogFactory factory, s } /// - /// Configures the bot action catalog to respond to any event using the specified condition and handler + /// Configures a new bot action to respond to any event using the specified condition and handler /// delegates. /// /// An instance of @@ -94,7 +102,7 @@ public static BotActionBuilder OnMessage(this BotActionCatalogFactory factory, D } /// - /// Configures the bot action catalog to respond to events using the specified condition and handler + /// Configures a new bot action to respond to events using the specified condition and handler /// delegates. /// /// An instance of @@ -108,7 +116,7 @@ public static BotActionBuilder OnMessage(this BotActionCatalogFactory factory, D /// /// A configured instance of that allows further customization of the bot action. /// - public static BotActionBuilder OnTextMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + public static BotActionBuilder OnText(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) { var actionBuilder = factory.OnUpdate(condition, handler); @@ -118,7 +126,7 @@ public static BotActionBuilder OnTextMessage(this BotActionCatalogFactory factor } /// - /// Configures the bot action catalog to respond to events using the specified condition and handler + /// Configures a new bot action to respond to events using the specified condition and handler /// delegates. /// /// An instance of @@ -132,7 +140,7 @@ public static BotActionBuilder OnTextMessage(this BotActionCatalogFactory factor /// /// A configured instance of that allows further customization of the bot action. /// - public static BotActionBuilder OnPhotoMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + public static BotActionBuilder OnPhoto(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) { var actionBuilder = factory.OnUpdate(condition, handler); @@ -142,7 +150,7 @@ public static BotActionBuilder OnPhotoMessage(this BotActionCatalogFactory facto } /// - /// Configures the bot action catalog to respond to events using the specified condition and handler + /// Configures a new bot action to respond to events using the specified condition and handler /// delegates. /// /// An instance of @@ -156,7 +164,7 @@ public static BotActionBuilder OnPhotoMessage(this BotActionCatalogFactory facto /// /// A configured instance of that allows further customization of the bot action. /// - public static BotActionBuilder OnAudioMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + public static BotActionBuilder OnAudio(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) { var actionBuilder = factory.OnUpdate(condition, handler); @@ -166,7 +174,7 @@ public static BotActionBuilder OnAudioMessage(this BotActionCatalogFactory facto } /// - /// Configures the bot action catalog to respond to events using the specified condition and handler + /// Configures a new bot action to respond to events using the specified condition and handler /// delegates. /// /// An instance of @@ -180,7 +188,7 @@ public static BotActionBuilder OnAudioMessage(this BotActionCatalogFactory facto /// /// A configured instance of that allows further customization of the bot action. /// - public static BotActionBuilder OnVideoMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + public static BotActionBuilder OnVideo(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) { var actionBuilder = factory.OnUpdate(condition, handler); @@ -190,7 +198,7 @@ public static BotActionBuilder OnVideoMessage(this BotActionCatalogFactory facto } /// - /// Configures the bot action catalog to respond to events using the specified condition and handler + /// Configures a new bot action to respond to events using the specified condition and handler /// delegates. /// /// An instance of @@ -204,7 +212,7 @@ public static BotActionBuilder OnVideoMessage(this BotActionCatalogFactory facto /// /// A configured instance of that allows further customization of the bot action. /// - public static BotActionBuilder OnVoiceMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + public static BotActionBuilder OnVoice(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) { var actionBuilder = factory.OnUpdate(condition, handler); @@ -212,4 +220,1707 @@ public static BotActionBuilder OnVoiceMessage(this BotActionCatalogFactory facto return actionBuilder; } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnDocument(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Document))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnSticker(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Sticker))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnLocation(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Location))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnContact(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Contact))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnVenue(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Venue))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnGame(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Game))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnVideoNote(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoNote))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnInvoice(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Invoice))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnSuccessfulPayment(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.SuccessfulPayment))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnConnectedWebsite(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ConnectedWebsite))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnNewChatMembers(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatMembers))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnLeftChatMember(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.LeftChatMember))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnNewChatTitle(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatTitle))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnNewChatPhoto(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatPhoto))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnPinnedMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.PinnedMessage))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnDeleteChatPhoto(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.DeleteChatPhoto))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnGroupChatCreated(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.GroupChatCreated))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnSupergroupChatCreated(this BotActionCatalogFactory factory, Delegate condition, + Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.SupergroupChatCreated))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnChannelChatCreated(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ChannelChatCreated))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnMigrateFromChatId(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.MigrateFromChatId))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnMigrateToChatId(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.MigrateToChatId))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnPollMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Poll))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnDice(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Dice))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition + /// and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnMessageAutoDeleteTimerChanged(this BotActionCatalogFactory factory, Delegate condition, + Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.MessageAutoDeleteTimerChanged))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnProximityAlertTriggered(this BotActionCatalogFactory factory, Delegate condition, + Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ProximityAlertTriggered))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnWebAppData(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.WebAppData))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnVideoChatScheduled(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatScheduled))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnVideoChatStarted(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatStarted))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnVideoChatEnded(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatEnded))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition + /// and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnVideoChatParticipantsInvited(this BotActionCatalogFactory factory, Delegate condition, + Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatParticipantsInvited))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnAnimation(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Animation))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnForumTopicCreated(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicCreated))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnForumTopicClosed(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicClosed))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnForumTopicReopened(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicReopened))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnForumTopicEdited(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicEdited))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnGeneralForumTopicHidden(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.GeneralForumTopicHidden))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnGeneralForumTopicUnhidden(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.GeneralForumTopicUnhidden))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnWriteAccessAllowed(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.WriteAccessAllowed))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnUsersShared(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.UsersShared))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnChatShared(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ChatShared))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnPassportData(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.PassportData))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnGiveawayCreated(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayCreated))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnGiveaway(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Giveaway))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnGiveawayWinners(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayWinners))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnGiveawayCompleted(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayCompleted))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnBoostAdded(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.BoostAdded))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnChatBackgroundSet(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ChatBackgroundSet))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnPaidMedia(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.PaidMedia))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnRefundedPayment(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.RefundedPayment))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to message events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnUnknownMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Unknown))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnInlineQuery(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.InlineQuery))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnChosenInlineResult(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChosenInlineResult))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnCallbackQuery(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.CallbackQuery))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnEditedMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedMessage))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnEditedChannelPost(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedChannelPost))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnShippingQuery(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ShippingQuery))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnPreCheckoutQuery(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.PreCheckoutQuery))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnPollUpdate(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Poll))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnPollAnswer(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.PollAnswer))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnMyChatMember(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MyChatMember))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnChatMember(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatMember))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnChatJoinRequest(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatJoinRequest))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnMessageReaction(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MessageReaction))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnMessageReactionCount(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MessageReactionCount))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnChatBoost(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatBoost))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnRemovedChatBoost(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.RemovedChatBoost))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnBusinessConnection(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.BusinessConnection))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnBusinessMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.BusinessMessage))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnEditedBusinessMessage(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedBusinessMessage))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to events using the specified condition and + /// handler delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnDeletedBusinessMessages(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.DeletedBusinessMessages))); + + return actionBuilder; + } + + /// + /// Configures a new bot action to respond to update events using the specified condition and handler + /// delegates. + /// + /// An instance of + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is + /// + /// + /// A delegate representing the action to take when the condition is met. + /// + /// + /// A configured instance of that allows further customization of the bot action. + /// + public static BotActionBuilder OnUnknownUpdate(this BotActionCatalogFactory factory, Delegate condition, Delegate handler) + { + var actionBuilder = factory.OnUpdate(condition, handler); + + actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Unknown))); + + return actionBuilder; + } } \ No newline at end of file From 52080c94810cf7d4284637d23febe06d926bd8cb Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Tue, 20 Aug 2024 15:10:15 +0200 Subject: [PATCH 46/66] feat: add support for typing notification, again --- src/Navigator/Strategy/NavigatorStrategy.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index b91cbb2..db71693 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -1,11 +1,14 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Navigator.Actions; using Navigator.Catalog; using Navigator.Catalog.Factory; using Navigator.Client; +using Navigator.Configuration.Options; using Navigator.Entities; using Navigator.Strategy.Classifier; using Navigator.Telegram; +using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using Chat = Navigator.Entities.Chat; @@ -22,6 +25,7 @@ public class NavigatorStrategy : INavigatorStrategy { private readonly BotActionCatalog _catalog; private readonly IUpdateClassifier _classifier; + private readonly INavigatorOptions _options; private readonly IServiceProvider _serviceProvider; /// @@ -31,11 +35,12 @@ public class NavigatorStrategy : INavigatorStrategy /// An instance of . /// An instance of /// . - public NavigatorStrategy(BotActionCatalogFactory catalogFactory, IUpdateClassifier classifier, + public NavigatorStrategy(BotActionCatalogFactory catalogFactory, IUpdateClassifier classifier, IOptions options, IServiceProvider serviceProvider) { _catalog = catalogFactory.Retrieve(); _classifier = classifier; + _options = options.Value; _serviceProvider = serviceProvider; } @@ -48,6 +53,11 @@ public NavigatorStrategy(BotActionCatalogFactory catalogFactory, IUpdateClassifi /// The object to be processed. public async Task Invoke(Update update) { + if (_options.TypingNotificationIsEnabled() && update.GetChatOrDefault() is { } chat) + { + await _serviceProvider.GetRequiredService().SendChatActionAsync(chat, ChatAction.Typing); + } + var actionType = await _classifier.Process(update); var relevantActions = _catalog.Retrieve(actionType); From e8674e063b63f15137bdd272bd09ad7f9ee2d4a3 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Tue, 20 Aug 2024 15:24:45 +0200 Subject: [PATCH 47/66] chore: add some documentation --- src/Navigator/Strategy/NavigatorStrategy.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index db71693..0849cf8 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -54,10 +54,8 @@ public NavigatorStrategy(BotActionCatalogFactory catalogFactory, IUpdateClassifi public async Task Invoke(Update update) { if (_options.TypingNotificationIsEnabled() && update.GetChatOrDefault() is { } chat) - { await _serviceProvider.GetRequiredService().SendChatActionAsync(chat, ChatAction.Typing); - } - + var actionType = await _classifier.Process(update); var relevantActions = _catalog.Retrieve(actionType); @@ -65,6 +63,14 @@ public async Task Invoke(Update update) await foreach (var action in FilterActionsThatCanHandleUpdate(relevantActions, update)) await ExecuteAction(action, update); } + + /// + /// Filters the given collection of by executing the condition of each action. + /// If the condition returns true, the action is included in the resulting collection and returned to the caller. + /// + /// The collection of to be filtered. + /// The object that triggered the execution of the strategy. + /// An of that passes the condition check. private async IAsyncEnumerable FilterActionsThatCanHandleUpdate(IEnumerable actions, Update update) { foreach (var action in actions) @@ -82,6 +88,13 @@ private async IAsyncEnumerable FilterActionsThatCanHandleUpdate(IEnum } } + /// + /// Executes the method of a after + /// retrieving the necessary input arguments. Arguments are retrieved by calling for each + /// input type specified in the . + /// + /// The to be executed. + /// The object that triggered the execution of the . private async Task ExecuteAction(BotAction action, Update update) { var numberOfInputs = action.Information.HandlerInputTypes.Length; From be510ac65bcf31244dc18f5d242c85a865def3e3 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Tue, 20 Aug 2024 16:14:53 +0200 Subject: [PATCH 48/66] feat: correct behavior with NavigatorOptions --- src/Navigator/Strategy/NavigatorStrategy.cs | 12 ++++++++---- src/Sample/Program.cs | 10 +++++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index 0849cf8..20f4020 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using Navigator.Actions; using Navigator.Catalog; using Navigator.Catalog.Factory; @@ -33,14 +32,15 @@ public class NavigatorStrategy : INavigatorStrategy /// /// An instance of . /// An instance of . + /// /// An instance of /// . - public NavigatorStrategy(BotActionCatalogFactory catalogFactory, IUpdateClassifier classifier, IOptions options, + public NavigatorStrategy(BotActionCatalogFactory catalogFactory, IUpdateClassifier classifier, INavigatorOptions options, IServiceProvider serviceProvider) { _catalog = catalogFactory.Retrieve(); _classifier = classifier; - _options = options.Value; + _options = options; _serviceProvider = serviceProvider; } @@ -84,7 +84,11 @@ private async IAsyncEnumerable FilterActionsThatCanHandleUpdate(IEnum arguments[i] = await GetArgument(inputType, update, action); } - if (await action.ExecuteCondition(arguments)) yield return action; + if (!await action.ExecuteCondition(arguments)) continue; + + yield return action; + + if (_options.MultipleActionsUsageIsEnabled() is false) break; } } diff --git a/src/Sample/Program.cs b/src/Sample/Program.cs index 70d0645..f7646d3 100644 --- a/src/Sample/Program.cs +++ b/src/Sample/Program.cs @@ -5,8 +5,9 @@ using Navigator.Client; using Navigator.Configuration; using Navigator.Configuration.Options; -using Navigator.Entities; using Telegram.Bot; +using Telegram.Bot.Types; +using Chat = Navigator.Entities.Chat; namespace Sample; @@ -23,12 +24,14 @@ public static void Main(string[] args) options.SetWebHookBaseUrl(builder.Configuration["BASE_WEBHOOK_URL"]!); options.SetTelegramToken(builder.Configuration["TELEGRAM_TOKEN"]!); options.EnableTypingNotification(); + options.EnableMultipleActionsUsage(); }); var app = builder.Build(); var bot = app.GetBot(); + // This action will be triggered if the user sends a message in the style of `/join `. bot.OnCommand("join", async (INavigatorClient client, Chat chat, string[] parameters) => { var result = string.Join(',', parameters); @@ -36,6 +39,11 @@ public static void Main(string[] args) await client.SendTextMessageAsync(chat, result); }); + // This action will be triggered for every message sent to the chat. Additionally in this code example, this action will be triggered + // only if NavigatorOptions.MultipleActionsUSageIsEnabled is set to true. + bot.OnMessage((Update _) => true, + async (INavigatorClient client, Chat chat) => { await client.SendTextMessageAsync(chat, "text received!"); }); + app.MapNavigator(); app.Run(); From 5958ea5e157944910908f5745676490ac02a898b Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Tue, 20 Aug 2024 16:15:33 +0200 Subject: [PATCH 49/66] refactor: convert Program to top level code --- src/Sample/Program.cs | 54 ++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/src/Sample/Program.cs b/src/Sample/Program.cs index f7646d3..9f64f53 100644 --- a/src/Sample/Program.cs +++ b/src/Sample/Program.cs @@ -9,43 +9,35 @@ using Telegram.Bot.Types; using Chat = Navigator.Entities.Chat; -namespace Sample; +var builder = WebApplication.CreateBuilder(args); -public class Program -{ - public static void Main(string[] args) - { - var builder = WebApplication.CreateBuilder(args); - - builder.Configuration.AddCommonConfiguration(); +builder.Configuration.AddCommonConfiguration(); - builder.Services.AddNavigator(options => - { - options.SetWebHookBaseUrl(builder.Configuration["BASE_WEBHOOK_URL"]!); - options.SetTelegramToken(builder.Configuration["TELEGRAM_TOKEN"]!); - options.EnableTypingNotification(); - options.EnableMultipleActionsUsage(); - }); +builder.Services.AddNavigator(options => +{ + options.SetWebHookBaseUrl(builder.Configuration["BASE_WEBHOOK_URL"]!); + options.SetTelegramToken(builder.Configuration["TELEGRAM_TOKEN"]!); + options.EnableTypingNotification(); + options.EnableMultipleActionsUsage(); +}); - var app = builder.Build(); +var app = builder.Build(); - var bot = app.GetBot(); +var bot = app.GetBot(); - // This action will be triggered if the user sends a message in the style of `/join `. - bot.OnCommand("join", async (INavigatorClient client, Chat chat, string[] parameters) => - { - var result = string.Join(',', parameters); +// This action will be triggered if the user sends a message in the style of `/join `. +bot.OnCommand("join", async (INavigatorClient client, Chat chat, string[] parameters) => +{ + var result = string.Join(',', parameters); - await client.SendTextMessageAsync(chat, result); - }); + await client.SendTextMessageAsync(chat, result); +}); - // This action will be triggered for every message sent to the chat. Additionally in this code example, this action will be triggered - // only if NavigatorOptions.MultipleActionsUSageIsEnabled is set to true. - bot.OnMessage((Update _) => true, - async (INavigatorClient client, Chat chat) => { await client.SendTextMessageAsync(chat, "text received!"); }); +// This action will be triggered for every message sent to the chat. Additionally in this code example, this action will be triggered +// only if NavigatorOptions.MultipleActionsUSageIsEnabled is set to true. +bot.OnMessage((Update _) => true, + async (INavigatorClient client, Chat chat) => { await client.SendTextMessageAsync(chat, "text received!"); }); - app.MapNavigator(); +app.MapNavigator(); - app.Run(); - } -} \ No newline at end of file +app.Run(); \ No newline at end of file From 227e8573d54084dd201760d71d4b73136a4a97f1 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 12:48:03 +0200 Subject: [PATCH 50/66] feat: refactor argument injection to use IArgumentTypeProvider --- src/Navigator/Strategy/NavigatorStrategy.cs | 39 +++++++++---------- .../TypeProvider/IArgumentTypeProvider.cs | 11 ++++++ 2 files changed, 29 insertions(+), 21 deletions(-) create mode 100644 src/Navigator/Strategy/TypeProvider/IArgumentTypeProvider.cs diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index 20f4020..8f8ce6b 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -4,13 +4,12 @@ using Navigator.Catalog.Factory; using Navigator.Client; using Navigator.Configuration.Options; -using Navigator.Entities; using Navigator.Strategy.Classifier; +using Navigator.Strategy.TypeProvider; using Navigator.Telegram; using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; -using Chat = Navigator.Entities.Chat; namespace Navigator.Strategy; @@ -115,24 +114,22 @@ private async Task ExecuteAction(BotAction action, Update update) private async Task GetArgument(Type inputType, Update update, BotAction action) { - var argument = inputType switch - { - not null when inputType == typeof(Update) - => update, - not null when inputType == typeof(Conversation) - => update.GetConversation(), - not null when inputType == typeof(Chat) - => update.GetConversation().Chat, - not null when inputType == typeof(Conversation) - => update.GetConversation().User, - not null when inputType == typeof(Bot) - => await _serviceProvider.GetRequiredService().GetProfile(), - not null when inputType == typeof(string[]) && action.Information.Category.Subkind == nameof(MessageEntityType.BotCommand) - => update.Message!.ExtractArguments(), - not null => _serviceProvider.GetRequiredService(inputType), - //TODO: this exception should never happen. - _ => throw new NavigatorException() - }; - return argument; + var argument = default(object?); + + var providers = _serviceProvider.GetServices(); + + foreach (var provider in providers) + argument = await provider.GetArgument(inputType, update, action); + + return argument ?? _serviceProvider.GetRequiredService(inputType); + } + + private async ValueTask GetArgumentUsingProviders(Type inputType, Update update, BotAction action) + { + var providers = _serviceProvider.GetServices(); + + foreach (var provider in providers) return await provider.GetArgument(inputType, update, action); + + return default; } } \ No newline at end of file diff --git a/src/Navigator/Strategy/TypeProvider/IArgumentTypeProvider.cs b/src/Navigator/Strategy/TypeProvider/IArgumentTypeProvider.cs new file mode 100644 index 0000000..0b242bd --- /dev/null +++ b/src/Navigator/Strategy/TypeProvider/IArgumentTypeProvider.cs @@ -0,0 +1,11 @@ +using Navigator.Actions; +using Telegram.Bot.Types; + +namespace Navigator.Strategy.TypeProvider; + +public interface IArgumentTypeProvider +{ + public ushort Priority { get; } + + public ValueTask GetArgument(Type type, Update update, BotAction action); +} \ No newline at end of file From 0752e255397f065a8de778725250e942a8b813bd Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 12:49:25 +0200 Subject: [PATCH 51/66] feat: add implementation of IArgumentTypeProvider for Navigator entities --- .../NavigatorEntitiesTypeProvider.cs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/Navigator/Strategy/TypeProvider/NavigatorEntitiesTypeProvider.cs diff --git a/src/Navigator/Strategy/TypeProvider/NavigatorEntitiesTypeProvider.cs b/src/Navigator/Strategy/TypeProvider/NavigatorEntitiesTypeProvider.cs new file mode 100644 index 0000000..bbfb021 --- /dev/null +++ b/src/Navigator/Strategy/TypeProvider/NavigatorEntitiesTypeProvider.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.DependencyInjection; +using Navigator.Actions; +using Navigator.Client; +using Navigator.Entities; +using Navigator.Telegram; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; +using Chat = Navigator.Entities.Chat; +using User = Navigator.Entities.User; + +namespace Navigator.Strategy.TypeProvider; + +internal sealed record NavigatorEntitiesTypeProvider : IArgumentTypeProvider +{ + private readonly IServiceProvider _serviceProvider; + + public NavigatorEntitiesTypeProvider(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + /// + public ushort Priority { get; } = 10000; + + + /// + public async ValueTask GetArgument(Type type, Update update, BotAction action) + { + return type switch + { + not null when type == typeof(Conversation) + => update.GetConversation(), + not null when type == typeof(Chat) + => update.GetConversation().Chat, + not null when type == typeof(User) + => update.GetConversation().User, + not null when type == typeof(Bot) + => await _serviceProvider.GetRequiredService().GetProfile(), + not null when type == typeof(string[]) && action.Information.Category.Subkind == nameof(MessageEntityType.BotCommand) + => update.Message!.ExtractArguments(), + _ => default + }; + } +} \ No newline at end of file From d4934d9243d75aed4fa0114cf1dc26d93e5ce33a Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 12:49:36 +0200 Subject: [PATCH 52/66] feat: add implementation of IArgumentTypeProvider for Telegram entities --- .../TelegramEntitiesTypeProvider.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/Navigator/Strategy/TypeProvider/TelegramEntitiesTypeProvider.cs diff --git a/src/Navigator/Strategy/TypeProvider/TelegramEntitiesTypeProvider.cs b/src/Navigator/Strategy/TypeProvider/TelegramEntitiesTypeProvider.cs new file mode 100644 index 0000000..6e0e3c4 --- /dev/null +++ b/src/Navigator/Strategy/TypeProvider/TelegramEntitiesTypeProvider.cs @@ -0,0 +1,32 @@ +using Navigator.Actions; +using Navigator.Telegram; +using Telegram.Bot.Types; + +namespace Navigator.Strategy.TypeProvider; + +internal sealed record TelegramEntitiesTypeProvider : IArgumentTypeProvider +{ + private readonly IServiceProvider _serviceProvider; + + public TelegramEntitiesTypeProvider(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + /// + public ushort Priority { get; } = 10000; + + public ValueTask GetArgument(Type type, Update update, BotAction action) + { + return ValueTask.FromResult(type switch + { + not null when type == typeof(Update) + => update, + not null when type == typeof(Chat) + => update.GetChatOrDefault(), + not null when type == typeof(User) + => update.GetUserOrDefault(), + _ => default + }); + } +} \ No newline at end of file From 0d3540657cecae05a80ab97a4ac44f0de720d6be Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 12:53:08 +0200 Subject: [PATCH 53/66] feat: add implementation of IArgumentTypeProvider for all possible Update types --- .../TelegramUpdateTypeProvider.cs | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/Navigator/Strategy/TypeProvider/TelegramUpdateTypeProvider.cs diff --git a/src/Navigator/Strategy/TypeProvider/TelegramUpdateTypeProvider.cs b/src/Navigator/Strategy/TypeProvider/TelegramUpdateTypeProvider.cs new file mode 100644 index 0000000..3da0233 --- /dev/null +++ b/src/Navigator/Strategy/TypeProvider/TelegramUpdateTypeProvider.cs @@ -0,0 +1,70 @@ +using Navigator.Actions; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; +using Telegram.Bot.Types.Payments; + +namespace Navigator.Strategy.TypeProvider; + +internal sealed record TelegramUpdateTypeProvider : IArgumentTypeProvider +{ + private readonly IServiceProvider _serviceProvider; + + public TelegramUpdateTypeProvider(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + /// + public ushort Priority => 10000; + + /// + public ValueTask GetArgument(Type type, Update update, BotAction action) + { + return ValueTask.FromResult(type switch + { + not null when type == typeof(Message) && update.Type == UpdateType.Message + => update.Message, + not null when type == typeof(InlineQuery) && update.Type == UpdateType.InlineQuery + => update.InlineQuery, + not null when type == typeof(ChosenInlineResult) && update.Type == UpdateType.ChosenInlineResult + => update.ChosenInlineResult, + not null when type == typeof(CallbackQuery) && update.Type == UpdateType.CallbackQuery + => update.CallbackQuery, + not null when type == typeof(Message) && update.Type == UpdateType.EditedMessage + => update.EditedMessage, + not null when type == typeof(Message) && update.Type == UpdateType.ChannelPost + => update.ChannelPost, + not null when type == typeof(Message) && update.Type == UpdateType.EditedChannelPost + => update.EditedChannelPost, + not null when type == typeof(ShippingQuery) && update.Type == UpdateType.ShippingQuery + => update.ShippingQuery, + not null when type == typeof(PreCheckoutQuery) && update.Type == UpdateType.PreCheckoutQuery + => update.PreCheckoutQuery, + not null when type == typeof(Poll) && update.Type == UpdateType.Poll + => update.Poll, + not null when type == typeof(PollAnswer) && update.Type == UpdateType.PollAnswer + => update.PollAnswer, + not null when type == typeof(ChatMemberUpdated) && update.Type == UpdateType.MyChatMember + => update.MyChatMember, + not null when type == typeof(ChatMember) && update.Type == UpdateType.ChatMember + => update.ChatMember, + not null when type == typeof(ChatJoinRequest) && update.Type == UpdateType.ChatJoinRequest + => update.ChatJoinRequest, + not null when type == typeof(MessageReactionUpdated) && update.Type == UpdateType.MessageReaction + => update.MessageReaction, + not null when type == typeof(MessageReactionCountUpdated) && update.Type == UpdateType.MessageReactionCount + => update.MessageReactionCount, + not null when type == typeof(ChatBoostRemoved) && update.Type == UpdateType.RemovedChatBoost + => update.RemovedChatBoost, + not null when type == typeof(BusinessConnection) && update.Type == UpdateType.BusinessConnection + => update.BusinessConnection, + not null when type == typeof(Message) && update.Type == UpdateType.BusinessMessage + => update.BusinessMessage, + not null when type == typeof(Message) && update.Type == UpdateType.EditedBusinessMessage + => update.EditedBusinessMessage, + not null when type == typeof(Message) && update.Type == UpdateType.DeletedBusinessMessages + => update.DeletedBusinessMessages, + _ => default + }); + } +} \ No newline at end of file From 3e887d66f803da5f8460443be0276507d92929f2 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 12:56:26 +0200 Subject: [PATCH 54/66] feat: update sample to showcase argument injection --- src/Sample/Program.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Sample/Program.cs b/src/Sample/Program.cs index 9f64f53..4a3f2d1 100644 --- a/src/Sample/Program.cs +++ b/src/Sample/Program.cs @@ -36,7 +36,10 @@ // This action will be triggered for every message sent to the chat. Additionally in this code example, this action will be triggered // only if NavigatorOptions.MultipleActionsUSageIsEnabled is set to true. bot.OnMessage((Update _) => true, - async (INavigatorClient client, Chat chat) => { await client.SendTextMessageAsync(chat, "text received!"); }); + async (INavigatorClient client, Chat chat, Message message) => + { + await client.SendTextMessageAsync(chat, $"message received: {message.MessageId}"); + }); app.MapNavigator(); From f5baaa04df2f21b0464f88167bed10cd07277bcd Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 15:10:17 +0200 Subject: [PATCH 55/66] feat: add implementation of IArgumentTypeProvider for all possible Message types --- .../TelegramMessageTypeProvider.cs | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 src/Navigator/Strategy/TypeProvider/TelegramMessageTypeProvider.cs diff --git a/src/Navigator/Strategy/TypeProvider/TelegramMessageTypeProvider.cs b/src/Navigator/Strategy/TypeProvider/TelegramMessageTypeProvider.cs new file mode 100644 index 0000000..04da91f --- /dev/null +++ b/src/Navigator/Strategy/TypeProvider/TelegramMessageTypeProvider.cs @@ -0,0 +1,141 @@ +using Navigator.Actions; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; +using Telegram.Bot.Types.Passport; +using Telegram.Bot.Types.Payments; + +namespace Navigator.Strategy.TypeProvider; + +internal sealed record TelegramMessageTypeProvider : IArgumentTypeProvider +{ + private readonly IServiceProvider _serviceProvider; + + public TelegramMessageTypeProvider(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + /// + public ushort Priority => 10000; + + /// + public ValueTask GetArgument(Type type, Update update, BotAction action) + { + if (update.Type != UpdateType.Message) return ValueTask.FromResult(default); + + return ValueTask.FromResult(type switch + { + not null when type == typeof(string) && update.Message!.Type == MessageType.Text + => update.Message.Text, + not null when type == typeof(PhotoSize[]) && update.Message!.Type == MessageType.Photo + => update.Message.Photo, + not null when type == typeof(Audio) && update.Message!.Type == MessageType.Audio + => update.Message.Audio, + not null when type == typeof(Video) && update.Message!.Type == MessageType.Video + => update.Message.Video, + not null when type == typeof(Voice) && update.Message!.Type == MessageType.Voice + => update.Message.Voice, + not null when type == typeof(Document) && update.Message!.Type == MessageType.Document + => update.Message.Document, + not null when type == typeof(Sticker) && update.Message!.Type == MessageType.Sticker + => update.Message.Sticker, + not null when type == typeof(Location) && update.Message!.Type == MessageType.Location + => update.Message.Location, + not null when type == typeof(Contact) && update.Message!.Type == MessageType.Contact + => update.Message.Contact, + not null when type == typeof(Venue) && update.Message!.Type == MessageType.Venue + => update.Message.Venue, + not null when type == typeof(Game) && update.Message!.Type == MessageType.Game + => update.Message.Game, + not null when type == typeof(VideoNote) && update.Message!.Type == MessageType.VideoNote + => update.Message.VideoNote, + not null when type == typeof(Invoice) && update.Message!.Type == MessageType.Invoice + => update.Message.Invoice, + not null when type == typeof(SuccessfulPayment) && update.Message!.Type == MessageType.SuccessfulPayment + => update.Message.SuccessfulPayment, + not null when type == typeof(string) && update.Message!.Type == MessageType.ConnectedWebsite + => update.Message.ConnectedWebsite, + not null when type == typeof(User[]) && update.Message!.Type == MessageType.NewChatMembers + => update.Message.NewChatMembers, + not null when type == typeof(User) && update.Message!.Type == MessageType.LeftChatMember + => update.Message.LeftChatMember, + not null when type == typeof(string) && update.Message!.Type == MessageType.NewChatTitle + => update.Message.NewChatTitle, + not null when type == typeof(PhotoSize[]) && update.Message!.Type == MessageType.NewChatPhoto + => update.Message.NewChatPhoto, + not null when type == typeof(Message) && update.Message!.Type == MessageType.PinnedMessage + => update.Message.PinnedMessage, + not null when type == typeof(PhotoSize[]) && update.Message!.Type == MessageType.DeleteChatPhoto + => update.Message.DeleteChatPhoto, + not null when type == typeof(Chat) && update.Message!.Type == MessageType.GroupChatCreated + => update.Message.Chat, + not null when type == typeof(Chat) && update.Message!.Type == MessageType.SupergroupChatCreated + => update.Message.Chat, + not null when type == typeof(Chat) && update.Message!.Type == MessageType.ChannelChatCreated + => update.Message.Chat, + not null when type == typeof(long) && update.Message!.Type == MessageType.MigrateFromChatId + => update.Message.MigrateFromChatId, + not null when type == typeof(long) && update.Message!.Type == MessageType.MigrateToChatId + => update.Message.MigrateToChatId, + not null when type == typeof(Poll) && update.Message!.Type == MessageType.Poll + => update.Message.Poll, + not null when type == typeof(Dice) && update.Message!.Type == MessageType.Dice + => update.Message.Dice, + not null when type == typeof(MessageAutoDeleteTimerChanged) && update.Message!.Type == MessageType.MessageAutoDeleteTimerChanged + => update.Message.MessageAutoDeleteTimerChanged, + not null when type == typeof(ProximityAlertTriggered) && update.Message!.Type == MessageType.ProximityAlertTriggered + => update.Message.ProximityAlertTriggered, + not null when type == typeof(WebAppData) && update.Message!.Type == MessageType.WebAppData + => update.Message.WebAppData, + not null when type == typeof(VideoChatScheduled) && update.Message!.Type == MessageType.VideoChatScheduled + => update.Message.VideoChatScheduled, + not null when type == typeof(VideoChatStarted) && update.Message!.Type == MessageType.VideoChatStarted + => update.Message.VideoChatStarted, + not null when type == typeof(VideoChatEnded) && update.Message!.Type == MessageType.VideoChatEnded + => update.Message.VideoChatEnded, + not null when type == typeof(VideoChatParticipantsInvited) && update.Message!.Type == MessageType.VideoChatParticipantsInvited + => update.Message.VideoChatParticipantsInvited, + not null when type == typeof(Animation) && update.Message!.Type == MessageType.Animation + => update.Message.Animation, + not null when type == typeof(ForumTopicCreated) && update.Message!.Type == MessageType.ForumTopicCreated + => update.Message.ForumTopicCreated, + not null when type == typeof(ForumTopicClosed) && update.Message!.Type == MessageType.ForumTopicClosed + => update.Message.ForumTopicClosed, + not null when type == typeof(ForumTopicReopened) && update.Message!.Type == MessageType.ForumTopicReopened + => update.Message.ForumTopicReopened, + not null when type == typeof(ForumTopicEdited) && update.Message!.Type == MessageType.ForumTopicEdited + => update.Message.ForumTopicEdited, + not null when type == typeof(GeneralForumTopicHidden) && update.Message!.Type == MessageType.GeneralForumTopicHidden + => update.Message.GeneralForumTopicHidden, + not null when type == typeof(GeneralForumTopicUnhidden) && update.Message!.Type == MessageType.GeneralForumTopicUnhidden + => update.Message.GeneralForumTopicUnhidden, + not null when type == typeof(WriteAccessAllowed) && update.Message!.Type == MessageType.WriteAccessAllowed + => update.Message.WriteAccessAllowed, + not null when type == typeof(UsersShared) && update.Message!.Type == MessageType.UsersShared + => update.Message.UsersShared, + not null when type == typeof(ChatShared) && update.Message!.Type == MessageType.ChatShared + => update.Message.ChatShared, + not null when type == typeof(Story) && update.Message!.Type == MessageType.Story + => update.Message.Story, + not null when type == typeof(PassportData) && update.Message!.Type == MessageType.PassportData + => update.Message.PassportData, + not null when type == typeof(GiveawayCreated) && update.Message!.Type == MessageType.GiveawayCreated + => update.Message.GiveawayCreated, + not null when type == typeof(Giveaway) && update.Message!.Type == MessageType.Giveaway + => update.Message.Giveaway, + not null when type == typeof(GiveawayWinners) && update.Message!.Type == MessageType.GiveawayWinners + => update.Message.GiveawayWinners, + not null when type == typeof(GiveawayCompleted) && update.Message!.Type == MessageType.GiveawayCompleted + => update.Message.GiveawayCompleted, + not null when type == typeof(ChatBoostAdded) && update.Message!.Type == MessageType.BoostAdded + => update.Message.BoostAdded, + not null when type == typeof(ChatBackground) && update.Message!.Type == MessageType.ChatBackgroundSet + => update.Message.ChatBackgroundSet, + not null when type == typeof(PaidMedia) && update.Message!.Type == MessageType.PaidMedia + => update.Message.PaidMedia, + not null when type == typeof(RefundedPayment) && update.Message!.Type == MessageType.RefundedPayment + => update.Message.RefundedPayment, + _ => default + }); + } +} \ No newline at end of file From 63d2df0b23c0aa76b295f282315e501e6908a2d9 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 15:10:30 +0200 Subject: [PATCH 56/66] feat: update sample again --- src/Sample/Program.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Sample/Program.cs b/src/Sample/Program.cs index 4a3f2d1..266a493 100644 --- a/src/Sample/Program.cs +++ b/src/Sample/Program.cs @@ -35,11 +35,12 @@ // This action will be triggered for every message sent to the chat. Additionally in this code example, this action will be triggered // only if NavigatorOptions.MultipleActionsUSageIsEnabled is set to true. -bot.OnMessage((Update _) => true, - async (INavigatorClient client, Chat chat, Message message) => - { - await client.SendTextMessageAsync(chat, $"message received: {message.MessageId}"); - }); +bot.OnMessage((Update _) => true, async (INavigatorClient client, Chat chat, Message message) => +{ + var text = $"message received: {message.MessageId}"; + + await client.SendTextMessageAsync(chat, text); +}); app.MapNavigator(); From f868fcbaa9d5417505dc0c064a857662798b455c Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 15:24:46 +0200 Subject: [PATCH 57/66] feat: update service collection & correct NavigatorStrategy --- src/Navigator/ServiceCollectionExtensions.cs | 7 +++++++ src/Navigator/Strategy/NavigatorStrategy.cs | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/Navigator/ServiceCollectionExtensions.cs b/src/Navigator/ServiceCollectionExtensions.cs index 2bc8e6f..c8060be 100644 --- a/src/Navigator/ServiceCollectionExtensions.cs +++ b/src/Navigator/ServiceCollectionExtensions.cs @@ -6,6 +6,7 @@ using Navigator.Hosted; using Navigator.Strategy; using Navigator.Strategy.Classifier; +using Navigator.Strategy.TypeProvider; namespace Navigator; @@ -33,6 +34,12 @@ public static NavigatorConfiguration AddNavigator(this IServiceCollection servic services.AddSingleton(); services.AddScoped(); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); services.AddHostedService(); diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index 8f8ce6b..dcaf8d5 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -119,8 +119,15 @@ private async Task ExecuteAction(BotAction action, Update update) var providers = _serviceProvider.GetServices(); foreach (var provider in providers) + { argument = await provider.GetArgument(inputType, update, action); + if (argument is not null) + { + break; + } + } + return argument ?? _serviceProvider.GetRequiredService(inputType); } From 722665085741124f470980cfcd076285000c6651 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 15:26:11 +0200 Subject: [PATCH 58/66] refactor: simplify implementations of IArgumentTypeProvider when possible --- .../Strategy/TypeProvider/TelegramEntitiesTypeProvider.cs | 7 ------- .../Strategy/TypeProvider/TelegramMessageTypeProvider.cs | 7 ------- .../Strategy/TypeProvider/TelegramUpdateTypeProvider.cs | 7 ------- 3 files changed, 21 deletions(-) diff --git a/src/Navigator/Strategy/TypeProvider/TelegramEntitiesTypeProvider.cs b/src/Navigator/Strategy/TypeProvider/TelegramEntitiesTypeProvider.cs index 6e0e3c4..4e36b7d 100644 --- a/src/Navigator/Strategy/TypeProvider/TelegramEntitiesTypeProvider.cs +++ b/src/Navigator/Strategy/TypeProvider/TelegramEntitiesTypeProvider.cs @@ -6,13 +6,6 @@ namespace Navigator.Strategy.TypeProvider; internal sealed record TelegramEntitiesTypeProvider : IArgumentTypeProvider { - private readonly IServiceProvider _serviceProvider; - - public TelegramEntitiesTypeProvider(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - /// public ushort Priority { get; } = 10000; diff --git a/src/Navigator/Strategy/TypeProvider/TelegramMessageTypeProvider.cs b/src/Navigator/Strategy/TypeProvider/TelegramMessageTypeProvider.cs index 04da91f..74c27e9 100644 --- a/src/Navigator/Strategy/TypeProvider/TelegramMessageTypeProvider.cs +++ b/src/Navigator/Strategy/TypeProvider/TelegramMessageTypeProvider.cs @@ -8,13 +8,6 @@ namespace Navigator.Strategy.TypeProvider; internal sealed record TelegramMessageTypeProvider : IArgumentTypeProvider { - private readonly IServiceProvider _serviceProvider; - - public TelegramMessageTypeProvider(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - /// public ushort Priority => 10000; diff --git a/src/Navigator/Strategy/TypeProvider/TelegramUpdateTypeProvider.cs b/src/Navigator/Strategy/TypeProvider/TelegramUpdateTypeProvider.cs index 3da0233..6b4d23c 100644 --- a/src/Navigator/Strategy/TypeProvider/TelegramUpdateTypeProvider.cs +++ b/src/Navigator/Strategy/TypeProvider/TelegramUpdateTypeProvider.cs @@ -7,13 +7,6 @@ namespace Navigator.Strategy.TypeProvider; internal sealed record TelegramUpdateTypeProvider : IArgumentTypeProvider { - private readonly IServiceProvider _serviceProvider; - - public TelegramUpdateTypeProvider(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - /// public ushort Priority => 10000; From da26ec8471a86ba15abaee18ed84bf0137befe4f Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 15:50:42 +0200 Subject: [PATCH 59/66] feat: upgrade NavigatorStrategy to respect cooldowns --- src/Navigator/Strategy/NavigatorStrategy.cs | 49 ++++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index dcaf8d5..774b484 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -1,3 +1,4 @@ +using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Navigator.Actions; using Navigator.Catalog; @@ -21,22 +22,24 @@ namespace Navigator.Strategy; /// public class NavigatorStrategy : INavigatorStrategy { + private readonly IMemoryCache _cache; private readonly BotActionCatalog _catalog; private readonly IUpdateClassifier _classifier; private readonly INavigatorOptions _options; private readonly IServiceProvider _serviceProvider; /// - /// Initializes a new instance of . + /// Initializes a new instance of the class. /// - /// An instance of . - /// An instance of . - /// - /// An instance of - /// . - public NavigatorStrategy(BotActionCatalogFactory catalogFactory, IUpdateClassifier classifier, INavigatorOptions options, - IServiceProvider serviceProvider) + /// The instance. + /// The instance. + /// The instance. + /// The instance. + /// The instance. + public NavigatorStrategy(IMemoryCache cache, BotActionCatalogFactory catalogFactory, IUpdateClassifier classifier, + INavigatorOptions options, IServiceProvider serviceProvider) { + _cache = cache; _catalog = catalogFactory.Retrieve(); _classifier = classifier; _options = options; @@ -59,9 +62,32 @@ public async Task Invoke(Update update) var relevantActions = _catalog.Retrieve(actionType); + relevantActions = relevantActions.Where(action => IsNotInCooldown(action, update)); + await foreach (var action in FilterActionsThatCanHandleUpdate(relevantActions, update)) await ExecuteAction(action, update); } + /// + /// Checks if the given is in cooldown. + /// + /// The object to be checked. + /// The object that triggered the execution of the . + /// true if the is in cooldown; otherwise, false. + private bool IsNotInCooldown(BotAction botAction, Update update) + { + return !_cache.TryGetValue(GenerateCacheKey(botAction, update), out _); + } + + /// + /// Generates a cache key based on the and . It ultimately uses the chat id, if available. + /// + /// The object to be used in the cache key. + /// The object to be used in the cache key. + /// A representing the cache key. + private static string GenerateCacheKey(BotAction botAction, Update update) + { + return $"{botAction.Id}:{update.GetChatOrDefault()?.Id}"; + } /// /// Filters the given collection of by executing the condition of each action. @@ -110,6 +136,8 @@ private async Task ExecuteAction(BotAction action, Update update) } await action.ExecuteHandler(arguments); + + if (action.Information.Cooldown.HasValue) _cache.Set(GenerateCacheKey(action, update), true, action.Information.Cooldown.Value); } private async Task GetArgument(Type inputType, Update update, BotAction action) @@ -122,10 +150,7 @@ private async Task ExecuteAction(BotAction action, Update update) { argument = await provider.GetArgument(inputType, update, action); - if (argument is not null) - { - break; - } + if (argument is not null) break; } return argument ?? _serviceProvider.GetRequiredService(inputType); From e7cc95c82829564f460cda8d81fb31ed7e091787 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 15:52:54 +0200 Subject: [PATCH 60/66] feat: delete store extension not much of a need now --- .../BotEntityTypeConfiguration.cs | 13 -- .../ChatEntityTypeConfiguration.cs | 33 --- .../ConversationEntityTypeConfiguration.cs | 16 -- .../UserEntityTypeConfiguration.cs | 33 --- .../Context/NavigatorDbContext.cs | 53 ----- .../Entities/Bot.cs | 22 -- .../Entities/Chat.cs | 77 ------- .../Entities/Conversation.cs | 51 ----- .../Entities/User.cs | 86 -------- .../Navigator.Extensions.Store.csproj | 32 --- .../NavigatorContextExtensions.cs | 44 ---- ...vigatorExtensionConfigurationExtensions.cs | 33 --- .../NavigatorStoreException.cs | 29 --- .../StoreNavigatorContextExtension.cs | 91 -------- src/Navigator.sln | 21 -- src/Sample.Store/Actions/EchoAction.cs | 16 -- src/Sample.Store/Actions/EchoActionHandler.cs | 29 --- ...0231009172135_InitialMigration.Designer.cs | 196 ------------------ .../20231009172135_InitialMigration.cs | 119 ----------- .../NavigatorDbContextModelSnapshot.cs | 193 ----------------- src/Sample.Store/Program.cs | 44 ---- src/Sample.Store/Sample.Store.csproj | 23 -- src/Sample.Store/app.db-shm | Bin 32768 -> 0 bytes src/Sample.Store/app.db-wal | 0 src/Sample.Store/appsettings.Development.json | 8 - src/Sample.Store/appsettings.json | 12 -- src/Sample.Testing/Sample.Testing.csproj | 25 --- src/Sample.Testing/TestFactory.cs | 27 --- 28 files changed, 1326 deletions(-) delete mode 100644 src/Navigator.Extensions.Store/Context/Configuration/BotEntityTypeConfiguration.cs delete mode 100644 src/Navigator.Extensions.Store/Context/Configuration/ChatEntityTypeConfiguration.cs delete mode 100644 src/Navigator.Extensions.Store/Context/Configuration/ConversationEntityTypeConfiguration.cs delete mode 100644 src/Navigator.Extensions.Store/Context/Configuration/UserEntityTypeConfiguration.cs delete mode 100644 src/Navigator.Extensions.Store/Context/NavigatorDbContext.cs delete mode 100644 src/Navigator.Extensions.Store/Entities/Bot.cs delete mode 100644 src/Navigator.Extensions.Store/Entities/Chat.cs delete mode 100644 src/Navigator.Extensions.Store/Entities/Conversation.cs delete mode 100644 src/Navigator.Extensions.Store/Entities/User.cs delete mode 100644 src/Navigator.Extensions.Store/Navigator.Extensions.Store.csproj delete mode 100644 src/Navigator.Extensions.Store/NavigatorContextExtensions.cs delete mode 100644 src/Navigator.Extensions.Store/NavigatorExtensionConfigurationExtensions.cs delete mode 100644 src/Navigator.Extensions.Store/NavigatorStoreException.cs delete mode 100644 src/Navigator.Extensions.Store/StoreNavigatorContextExtension.cs delete mode 100644 src/Sample.Store/Actions/EchoAction.cs delete mode 100644 src/Sample.Store/Actions/EchoActionHandler.cs delete mode 100644 src/Sample.Store/Migrations/20231009172135_InitialMigration.Designer.cs delete mode 100644 src/Sample.Store/Migrations/20231009172135_InitialMigration.cs delete mode 100644 src/Sample.Store/Migrations/NavigatorDbContextModelSnapshot.cs delete mode 100644 src/Sample.Store/Program.cs delete mode 100644 src/Sample.Store/Sample.Store.csproj delete mode 100644 src/Sample.Store/app.db-shm delete mode 100644 src/Sample.Store/app.db-wal delete mode 100644 src/Sample.Store/appsettings.Development.json delete mode 100644 src/Sample.Store/appsettings.json delete mode 100644 src/Sample.Testing/Sample.Testing.csproj delete mode 100644 src/Sample.Testing/TestFactory.cs diff --git a/src/Navigator.Extensions.Store/Context/Configuration/BotEntityTypeConfiguration.cs b/src/Navigator.Extensions.Store/Context/Configuration/BotEntityTypeConfiguration.cs deleted file mode 100644 index 4bd35b3..0000000 --- a/src/Navigator.Extensions.Store/Context/Configuration/BotEntityTypeConfiguration.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Navigator.Entities; - -namespace Navigator.Extensions.Store.Context.Configuration; - -internal class BotEntityTypeConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.HasBaseType(); - } -} \ No newline at end of file diff --git a/src/Navigator.Extensions.Store/Context/Configuration/ChatEntityTypeConfiguration.cs b/src/Navigator.Extensions.Store/Context/Configuration/ChatEntityTypeConfiguration.cs deleted file mode 100644 index 1e14d3b..0000000 --- a/src/Navigator.Extensions.Store/Context/Configuration/ChatEntityTypeConfiguration.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Text.Json; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.ChangeTracking; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Navigator.Extensions.Store.Entities; - -namespace Navigator.Extensions.Store.Context.Configuration; - -internal class ChatEntityTypeConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => e.Id); - - builder.Property(e => e.Title); - builder.Property(e => e.Type); - builder.Property(e => e.IsForum); - - builder.Property(e => e.FirstInteractionAt) - .IsRequired(); - - builder.HasMany(e => e.Users) - .WithMany(e => e.Chats) - .UsingEntity( - r => r.HasOne(e => e.User) - .WithMany(e => e.Conversations).HasForeignKey(e=> e.UserId), - l => l.HasOne(e => e.Chat) - .WithMany(e => e.Conversations).HasForeignKey(e=> e.ChatId)); - // builder.HasMany(e => e.Users) - // .WithMany(e => e.Chats) - // .UsingEntity(); - } -} \ No newline at end of file diff --git a/src/Navigator.Extensions.Store/Context/Configuration/ConversationEntityTypeConfiguration.cs b/src/Navigator.Extensions.Store/Context/Configuration/ConversationEntityTypeConfiguration.cs deleted file mode 100644 index 7e1e90a..0000000 --- a/src/Navigator.Extensions.Store/Context/Configuration/ConversationEntityTypeConfiguration.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Text.Json; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.ChangeTracking; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Navigator.Extensions.Store.Entities; - -namespace Navigator.Extensions.Store.Context.Configuration; - -internal class ConversationEntityTypeConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.Property(e => e.FirstInteractionAt) - .IsRequired(); - } -} \ No newline at end of file diff --git a/src/Navigator.Extensions.Store/Context/Configuration/UserEntityTypeConfiguration.cs b/src/Navigator.Extensions.Store/Context/Configuration/UserEntityTypeConfiguration.cs deleted file mode 100644 index 5b59d6f..0000000 --- a/src/Navigator.Extensions.Store/Context/Configuration/UserEntityTypeConfiguration.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Text.Json; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.ChangeTracking; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Navigator.Extensions.Store.Entities; - -namespace Navigator.Extensions.Store.Context.Configuration; - -internal class UserEntityTypeConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => e.Id); - - builder.Property(e => e.Username); - builder.Property(e => e.FirstName); - builder.Property(e => e.LastName); - builder.Property(e => e.LanguageCode); - builder.Property(e => e.IsPremium); - builder.Property(e => e.HasBotInAttachmentMenu); - - builder.Property(e => e.FirstInteractionAt) - .IsRequired(); - - // builder.HasMany(e => e.Chats) - // .WithMany(e => e.Users) - // .UsingEntity( - // r => r.HasOne(e => e.Chat) - // .WithMany(e => e.Conversations), - // l => l.HasOne(e => e.User) - // .WithMany(e => e.Conversations)); - } -} \ No newline at end of file diff --git a/src/Navigator.Extensions.Store/Context/NavigatorDbContext.cs b/src/Navigator.Extensions.Store/Context/NavigatorDbContext.cs deleted file mode 100644 index 9c0c99d..0000000 --- a/src/Navigator.Extensions.Store/Context/NavigatorDbContext.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Navigator.Extensions.Store.Context.Configuration; -using Navigator.Extensions.Store.Entities; - -namespace Navigator.Extensions.Store.Context; - -/// -/// Navigator Store Context -/// -public class NavigatorDbContext : DbContext -{ - - /// - protected NavigatorDbContext() - { - } - - /// - public NavigatorDbContext(DbContextOptions options) : base(options) - { - } - - /// - /// Bots. - /// - public required DbSet Bots { get; set; } - - /// - /// Users. - /// - public required DbSet Users { get; set; } - - /// - /// Chats. - /// - public required DbSet Chats { get; set; } - - /// - /// Conversations. - /// - public required DbSet Conversations { get; set; } - - /// - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - modelBuilder.ApplyConfiguration(new BotEntityTypeConfiguration()); - modelBuilder.ApplyConfiguration(new UserEntityTypeConfiguration()); - modelBuilder.ApplyConfiguration(new ChatEntityTypeConfiguration()); - modelBuilder.ApplyConfiguration(new ConversationEntityTypeConfiguration()); - } -} \ No newline at end of file diff --git a/src/Navigator.Extensions.Store/Entities/Bot.cs b/src/Navigator.Extensions.Store/Entities/Bot.cs deleted file mode 100644 index 8875e39..0000000 --- a/src/Navigator.Extensions.Store/Entities/Bot.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Navigator.Extensions.Store.Entities; - -/// -/// Bot. -/// -public class Bot : User -{ - /// - /// Internal constructor. - /// - protected Bot() - { - } - - /// - /// Bot constructor from - /// - /// - public Bot(Navigator.Entities.Bot bot) : base(bot) - { - } -} \ No newline at end of file diff --git a/src/Navigator.Extensions.Store/Entities/Chat.cs b/src/Navigator.Extensions.Store/Entities/Chat.cs deleted file mode 100644 index 5148924..0000000 --- a/src/Navigator.Extensions.Store/Entities/Chat.cs +++ /dev/null @@ -1,77 +0,0 @@ -using Navigator.Entities; - -namespace Navigator.Extensions.Store.Entities; - -/// -/// Chat. -/// -public class Chat -{ - /// - /// Internal constructor. - /// - protected Chat() - { - Users = new List(); - Conversations = new List(); - } - - /// - /// Chat constructor from - /// - /// - public Chat(Navigator.Entities.Chat chat) - { - Id = chat.Id; - Title = chat.Title; - Type = chat.Type; - IsForum = chat.IsForum; - - FirstInteractionAt = DateTime.UtcNow; - - Users = new List(); - Conversations = new List(); - } - - - /// - /// Id of the chat. - /// - public long Id { get; set; } - - /// - /// Title of the chat. - /// - /// Optional. - /// - /// - public string? Title { get; set; } - - /// - /// Type of the chat, can be any of . - /// - public Navigator.Entities.Chat.ChatType Type { get; set; } - - /// - /// If the supergroup chat is a forum (has topics enabled). - /// - /// Optional. - /// - /// - public bool? IsForum { get; set; } - - /// - /// Date of first interaction for this chat. - /// - public DateTime FirstInteractionAt { get; set; } - - /// - /// Users related to the chat. - /// - public ICollection Users { get; set; } - - /// - /// Conversations related to the chat. - /// - public ICollection Conversations { get; set; } -} \ No newline at end of file diff --git a/src/Navigator.Extensions.Store/Entities/Conversation.cs b/src/Navigator.Extensions.Store/Entities/Conversation.cs deleted file mode 100644 index 7045f6c..0000000 --- a/src/Navigator.Extensions.Store/Entities/Conversation.cs +++ /dev/null @@ -1,51 +0,0 @@ -namespace Navigator.Extensions.Store.Entities; - -/// -/// Conversation. -/// -public class Conversation -{ - /// - /// Internal constructor. - /// - protected Conversation() - { - } - - /// - /// Conversation constructor. - /// - /// - /// - public Conversation(User user, Chat chat) - { - UserId = user.Id; - ChatId = chat.Id; - FirstInteractionAt = DateTime.UtcNow; - } - - /// - /// Id of the user. - /// - public long UserId { get; set; } - - /// - /// User. - /// - public User User { get; set; } = null!; - - /// - /// Id of the chat. - /// - public long ChatId { get; set; } - - /// - /// Chat. - /// - public Chat Chat { get; set; } = null!; - - /// - /// Date of first interaction for this chat. - /// - public DateTime FirstInteractionAt { get; set; } -} \ No newline at end of file diff --git a/src/Navigator.Extensions.Store/Entities/User.cs b/src/Navigator.Extensions.Store/Entities/User.cs deleted file mode 100644 index cad01e3..0000000 --- a/src/Navigator.Extensions.Store/Entities/User.cs +++ /dev/null @@ -1,86 +0,0 @@ -namespace Navigator.Extensions.Store.Entities; - -/// -/// Chat. -/// -public class User -{ - /// - /// Internal constructor. - /// - protected User() - { - Chats = new List(); - Conversations = new List(); - } - - /// - /// User constructor from - /// - /// - public User(Navigator.Entities.User user) - { - Id = user.Id; - Username = user.Username; - FirstName = user.LastName; - LastName = user.LastName; - LanguageCode = user.LanguageCode; - IsPremium = user.IsPremium; - HasBotInAttachmentMenu = user.HasBotInAttachmentMenu; - - FirstInteractionAt = DateTime.UtcNow; - - Chats = new List(); - Conversations = new List(); - } - - /// - /// Id of the user. - /// - public long Id { get; set; } - - /// - /// Username of the user. - /// - public string? Username { get; set; } - - /// - /// First name of the user. - /// - public string? FirstName { get; set; } - - /// - /// Last name of the user. - /// - public string? LastName { get; set; } - - /// - /// Language code of the user. - /// - public string? LanguageCode { get; set; } - - /// - /// True if the user is premium. - /// - public bool? IsPremium { get; set; } - - /// - /// True if the user has added the bot to the attachment menu. - /// - public bool? HasBotInAttachmentMenu { get; set; } - - /// - /// Chats related to the user. - /// - public IList Chats { get; set; } - - /// - /// Conversations related to the user. - /// - public ICollection Conversations { get; set; } - - /// - /// Date of first interaction for this chat. - /// - public DateTime FirstInteractionAt { get; set; } -} \ No newline at end of file diff --git a/src/Navigator.Extensions.Store/Navigator.Extensions.Store.csproj b/src/Navigator.Extensions.Store/Navigator.Extensions.Store.csproj deleted file mode 100644 index e7a43fb..0000000 --- a/src/Navigator.Extensions.Store/Navigator.Extensions.Store.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - - net8.0 - true - enable - true - Navigator.Extensions.Store - Lucas Maximiliano Marino - Persistence extension for Navigator Framework bots, requires provider implementations. - https://github.com/navigatorframework/navigator - https://github.com/navigatorframework/navigator - https://raw.githubusercontent.com/navigatorframework/navigator/master/assets/logo.png - Store, Bot, Extension, Navigator - true - AGPL-3.0-only - Copyright © Lucas Maximiliano Marino 2023 - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - diff --git a/src/Navigator.Extensions.Store/NavigatorContextExtensions.cs b/src/Navigator.Extensions.Store/NavigatorContextExtensions.cs deleted file mode 100644 index dad3d45..0000000 --- a/src/Navigator.Extensions.Store/NavigatorContextExtensions.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Navigator.Context; -using Navigator.Extensions.Store.Context; - -namespace Navigator.Extensions.Store; - -/// -/// Extensions for . -/// -public static class NavigatorContextExtensions -{ - #region NavigatorStore - - /// - /// Navigator store. - /// - /// - /// - /// - public static NavigatorDbContext Store(this INavigatorContext navigatorContext) - { - var store = navigatorContext.StoreOrDefault(); - - return store ?? throw new NavigatorException($"Navigator store not found."); - } - - /// - /// Navigator store. - /// - /// - /// - public static NavigatorDbContext? StoreOrDefault(this INavigatorContext navigatorContext) - { - var store = navigatorContext.Extensions.GetValueOrDefault(StoreNavigatorContextExtension.StoreDbContext); - - if (store is NavigatorDbContext db) - { - return db; - } - - return default; - } - - #endregion -} \ No newline at end of file diff --git a/src/Navigator.Extensions.Store/NavigatorExtensionConfigurationExtensions.cs b/src/Navigator.Extensions.Store/NavigatorExtensionConfigurationExtensions.cs deleted file mode 100644 index 18e36a7..0000000 --- a/src/Navigator.Extensions.Store/NavigatorExtensionConfigurationExtensions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Navigator.Configuration; -using Navigator.Configuration.Extensions; -using Navigator.Extensions.Store.Context; - -namespace Navigator.Extensions.Store; - -/// -/// Extensions for configuring the store in Navigator. -/// -public static class NavigatorExtensionConfigurationExtensions -{ - /// - /// Configure the navigator store. - /// - /// - /// - /// - public static NavigatorConfiguration Store(this NavigatorExtensionConfiguration extensionConfiguration, Action? dbContextOptions = default) - { - var temporal = new DbContextOptionsBuilder(); - - dbContextOptions?.Invoke(temporal); - - return extensionConfiguration.Extension(configuration => - { - configuration.Services.AddDbContext(dbContextOptions); - - configuration.Services.AddScoped(); - }); - } -} \ No newline at end of file diff --git a/src/Navigator.Extensions.Store/NavigatorStoreException.cs b/src/Navigator.Extensions.Store/NavigatorStoreException.cs deleted file mode 100644 index c9af92f..0000000 --- a/src/Navigator.Extensions.Store/NavigatorStoreException.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Runtime.Serialization; - -namespace Navigator.Extensions.Store; - -/// -/// Navigator Store exception. -/// -public class NavigatorStoreException : NavigatorException -{ - /// - public NavigatorStoreException() - { - } - - /// - protected NavigatorStoreException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - /// - public NavigatorStoreException(string? message) : base(message) - { - } - - /// - public NavigatorStoreException(string? message, Exception? innerException) : base(message, innerException) - { - } -} \ No newline at end of file diff --git a/src/Navigator.Extensions.Store/StoreNavigatorContextExtension.cs b/src/Navigator.Extensions.Store/StoreNavigatorContextExtension.cs deleted file mode 100644 index 7720018..0000000 --- a/src/Navigator.Extensions.Store/StoreNavigatorContextExtension.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Caching.Memory; -using Navigator.Context; -using Navigator.Context.Builder.Options; -using Navigator.Extensions.Store.Context; -using Navigator.Extensions.Store.Entities; - -namespace Navigator.Extensions.Store; - -internal class StoreNavigatorContextExtension : INavigatorContextExtension -{ - public const string StoreDbContext = "_navigator.extensions.store.dbcontext"; - - private readonly NavigatorDbContext _dbContext; - private readonly IMemoryCache _memoryCache; - - public StoreNavigatorContextExtension(NavigatorDbContext dbContext, IMemoryCache memoryCache) - { - _dbContext = dbContext; - _memoryCache = memoryCache; - } - - public async Task Extend(INavigatorContext navigatorContext, INavigatorContextBuilderOptions builderOptions) - { - navigatorContext.Extensions.TryAdd(StoreDbContext, _dbContext); - - if (_memoryCache.Get(navigatorContext.Conversation.GetHashCode()) is not null) - { - return navigatorContext; - } - - if (await _dbContext.Conversations - .Where(e => e.User.Id == navigatorContext.Conversation.User.Id) - .Where(e => navigatorContext.Conversation.Chat != null && - e.Chat.Id == navigatorContext.Conversation.Chat.Id) - .AnyAsync()) - { - _memoryCache.Set(navigatorContext.Conversation.GetHashCode(), true); - - return navigatorContext; - } - - var user = await TryStoreUserAsync(navigatorContext.Conversation); - var chat = await TryStoreChatAsync(navigatorContext.Conversation); - await TryStoreConversationAsync(user, chat); - - await _dbContext.SaveChangesAsync(); - - _memoryCache.Set(navigatorContext.Conversation.GetHashCode(), true); - - return navigatorContext; - } - - private async Task TryStoreUserAsync(Navigator.Entities.Conversation source) - { - if (await _dbContext.Users.AnyAsync(user => user.Id == source.User.Id)) return default; - - var user = source.User is Navigator.Entities.Bot bot - ? new Bot(bot) - : new User(source.User); - - await _dbContext.Users.AddAsync(user); - - return user; - } - - private async Task TryStoreChatAsync(Navigator.Entities.Conversation source) - { - if (source.Chat is null) return default; - - if (await _dbContext.Chats.AnyAsync(chat => chat.Id == source.Chat.Id)) return default; - - var chat = new Chat(source.Chat); - - await _dbContext.Chats.AddAsync(chat); - - return chat; - } - - private async Task TryStoreConversationAsync(User? user, Chat? chat) - { - if (user is null || chat is null) return; - - user.Chats.Add(chat); - chat.Users.Add(user); - - var conversation = new Conversation(user, chat); - - await _dbContext.Conversations.AddAsync(conversation); - } -} \ No newline at end of file diff --git a/src/Navigator.sln b/src/Navigator.sln index e52b066..49d3e9b 100644 --- a/src/Navigator.sln +++ b/src/Navigator.sln @@ -3,16 +3,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Navigator", "Navigator\Navi EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Packages", "Packages", "{A6DF6F5F-F784-4EF1-97D1-C3DDD2E66B5E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Navigator.Extensions.Store", "Navigator.Extensions.Store\Navigator.Extensions.Store.csproj", "{E7D6F33B-C30E-4ED2-878C-B2F899CF1805}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Testing", "Testing", "{24315212-C904-4479-BFA0-F1C830C32D82}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample", "Sample\Sample.csproj", "{3954357B-17C7-4091-9A9E-A1FC7E7B680D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.Testing", "Sample.Testing\Sample.Testing.csproj", "{5D012C90-4E38-48C0-A4FC-B459799D9B57}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.Store", "Sample.Store\Sample.Store.csproj", "{05843F22-918E-43BB-B6E9-BE112A6B180F}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".solution-items", ".solution-items", "{731D9036-DAE1-4300-825D-37C6F25C4F60}" ProjectSection(SolutionItems) = preProject ..\.github\workflows\package.navigator.yml = ..\.github\workflows\package.navigator.yml @@ -30,28 +24,13 @@ Global {6DBAD041-6623-4903-9939-254FDC4EBD60}.Debug|Any CPU.Build.0 = Debug|Any CPU {6DBAD041-6623-4903-9939-254FDC4EBD60}.Release|Any CPU.ActiveCfg = Release|Any CPU {6DBAD041-6623-4903-9939-254FDC4EBD60}.Release|Any CPU.Build.0 = Release|Any CPU - {E7D6F33B-C30E-4ED2-878C-B2F899CF1805}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E7D6F33B-C30E-4ED2-878C-B2F899CF1805}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E7D6F33B-C30E-4ED2-878C-B2F899CF1805}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E7D6F33B-C30E-4ED2-878C-B2F899CF1805}.Release|Any CPU.Build.0 = Release|Any CPU {3954357B-17C7-4091-9A9E-A1FC7E7B680D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3954357B-17C7-4091-9A9E-A1FC7E7B680D}.Debug|Any CPU.Build.0 = Debug|Any CPU {3954357B-17C7-4091-9A9E-A1FC7E7B680D}.Release|Any CPU.ActiveCfg = Release|Any CPU {3954357B-17C7-4091-9A9E-A1FC7E7B680D}.Release|Any CPU.Build.0 = Release|Any CPU - {5D012C90-4E38-48C0-A4FC-B459799D9B57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5D012C90-4E38-48C0-A4FC-B459799D9B57}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5D012C90-4E38-48C0-A4FC-B459799D9B57}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5D012C90-4E38-48C0-A4FC-B459799D9B57}.Release|Any CPU.Build.0 = Release|Any CPU - {05843F22-918E-43BB-B6E9-BE112A6B180F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {05843F22-918E-43BB-B6E9-BE112A6B180F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {05843F22-918E-43BB-B6E9-BE112A6B180F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {05843F22-918E-43BB-B6E9-BE112A6B180F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution - {E7D6F33B-C30E-4ED2-878C-B2F899CF1805} = {A6DF6F5F-F784-4EF1-97D1-C3DDD2E66B5E} {6DBAD041-6623-4903-9939-254FDC4EBD60} = {A6DF6F5F-F784-4EF1-97D1-C3DDD2E66B5E} {3954357B-17C7-4091-9A9E-A1FC7E7B680D} = {24315212-C904-4479-BFA0-F1C830C32D82} - {5D012C90-4E38-48C0-A4FC-B459799D9B57} = {24315212-C904-4479-BFA0-F1C830C32D82} - {05843F22-918E-43BB-B6E9-BE112A6B180F} = {24315212-C904-4479-BFA0-F1C830C32D82} EndGlobalSection EndGlobal diff --git a/src/Sample.Store/Actions/EchoAction.cs b/src/Sample.Store/Actions/EchoAction.cs deleted file mode 100644 index c0c882e..0000000 --- a/src/Sample.Store/Actions/EchoAction.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Navigator.Bundled.Actions.Messages; -using Navigator.Context.Accessor; - -namespace Sample.Store.Actions; - -public class EchoAction : TextAction -{ - public EchoAction(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - } - - public override bool CanHandleCurrentContext() - { - return !string.IsNullOrWhiteSpace(Text); - } -} \ No newline at end of file diff --git a/src/Sample.Store/Actions/EchoActionHandler.cs b/src/Sample.Store/Actions/EchoActionHandler.cs deleted file mode 100644 index 535fe43..0000000 --- a/src/Sample.Store/Actions/EchoActionHandler.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using Navigator.Actions; -using Navigator.Context.Accessor; -using Navigator.Extensions.Store; -using Telegram.Bot; - -namespace Sample.Store.Actions; - -public class EchoActionHandler : ActionHandler -{ - public EchoActionHandler(INavigatorContextAccessor navigatorContextAccessor) : base(navigatorContextAccessor) - { - } - - public override async Task Handle(EchoAction action, CancellationToken cancellationToken) - { - var firstInteraction = await Context.Store().Users - .Where(e => e.Id == Context.Conversation.User.Id) - .Select(user => user.FirstInteractionAt) - .FirstAsync(cancellationToken); - - await Context.Client.SendTextMessageAsync(action.ChatId, $"{action.Text}\nFirst seen: {firstInteraction}", cancellationToken: cancellationToken); - - return Success(); - } -} \ No newline at end of file diff --git a/src/Sample.Store/Migrations/20231009172135_InitialMigration.Designer.cs b/src/Sample.Store/Migrations/20231009172135_InitialMigration.Designer.cs deleted file mode 100644 index 13266ca..0000000 --- a/src/Sample.Store/Migrations/20231009172135_InitialMigration.Designer.cs +++ /dev/null @@ -1,196 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Navigator.Extensions.Store.Context; - -#nullable disable - -namespace Sample.Store.Migrations -{ - [DbContext(typeof(NavigatorDbContext))] - [Migration("20231009172135_InitialMigration")] - partial class InitialMigration - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "7.0.11"); - - modelBuilder.Entity("Navigator.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Discriminator") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("FirstName") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("HasBotInAttachmentMenu") - .HasColumnType("INTEGER"); - - b.Property("IsPremium") - .HasColumnType("INTEGER"); - - b.Property("LanguageCode") - .HasColumnType("TEXT"); - - b.Property("LastName") - .HasColumnType("TEXT"); - - b.Property("Username") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("User"); - - b.HasDiscriminator("Discriminator").HasValue("User"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("Navigator.Extensions.Store.Entities.Chat", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("FirstInteractionAt") - .HasColumnType("TEXT"); - - b.Property("IsForum") - .HasColumnType("INTEGER"); - - b.Property("Title") - .HasColumnType("TEXT"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("Chats"); - }); - - modelBuilder.Entity("Navigator.Extensions.Store.Entities.Conversation", b => - { - b.Property("ChatId") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("INTEGER"); - - b.Property("FirstInteractionAt") - .HasColumnType("TEXT"); - - b.HasKey("ChatId", "UserId"); - - b.HasIndex("UserId"); - - b.ToTable("Conversations"); - }); - - modelBuilder.Entity("Navigator.Extensions.Store.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Discriminator") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("FirstInteractionAt") - .HasColumnType("TEXT"); - - b.Property("FirstName") - .HasColumnType("TEXT"); - - b.Property("HasBotInAttachmentMenu") - .HasColumnType("INTEGER"); - - b.Property("IsPremium") - .HasColumnType("INTEGER"); - - b.Property("LanguageCode") - .HasColumnType("TEXT"); - - b.Property("LastName") - .HasColumnType("TEXT"); - - b.Property("Username") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("Users"); - - b.HasDiscriminator("Discriminator").HasValue("User"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("Navigator.Entities.Bot", b => - { - b.HasBaseType("Navigator.Entities.User"); - - b.Property("CanJoinGroups") - .HasColumnType("INTEGER"); - - b.Property("CanReadAllGroupMessages") - .HasColumnType("INTEGER"); - - b.Property("SupportsInlineQueries") - .HasColumnType("INTEGER"); - - b.HasDiscriminator().HasValue("Bot"); - }); - - modelBuilder.Entity("Navigator.Extensions.Store.Entities.Bot", b => - { - b.HasBaseType("Navigator.Extensions.Store.Entities.User"); - - b.HasDiscriminator().HasValue("Bot"); - }); - - modelBuilder.Entity("Navigator.Extensions.Store.Entities.Conversation", b => - { - b.HasOne("Navigator.Extensions.Store.Entities.Chat", "Chat") - .WithMany("Conversations") - .HasForeignKey("ChatId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Navigator.Extensions.Store.Entities.User", "User") - .WithMany("Conversations") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chat"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Navigator.Extensions.Store.Entities.Chat", b => - { - b.Navigation("Conversations"); - }); - - modelBuilder.Entity("Navigator.Extensions.Store.Entities.User", b => - { - b.Navigation("Conversations"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/Sample.Store/Migrations/20231009172135_InitialMigration.cs b/src/Sample.Store/Migrations/20231009172135_InitialMigration.cs deleted file mode 100644 index 64950a5..0000000 --- a/src/Sample.Store/Migrations/20231009172135_InitialMigration.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Sample.Store.Migrations -{ - /// - public partial class InitialMigration : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Chats", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Title = table.Column(type: "TEXT", nullable: true), - Type = table.Column(type: "INTEGER", nullable: false), - IsForum = table.Column(type: "INTEGER", nullable: true), - FirstInteractionAt = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Chats", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "User", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Username = table.Column(type: "TEXT", nullable: true), - FirstName = table.Column(type: "TEXT", nullable: false), - LastName = table.Column(type: "TEXT", nullable: true), - LanguageCode = table.Column(type: "TEXT", nullable: true), - IsPremium = table.Column(type: "INTEGER", nullable: true), - HasBotInAttachmentMenu = table.Column(type: "INTEGER", nullable: true), - Discriminator = table.Column(type: "TEXT", nullable: false), - CanJoinGroups = table.Column(type: "INTEGER", nullable: true), - CanReadAllGroupMessages = table.Column(type: "INTEGER", nullable: true), - SupportsInlineQueries = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_User", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "Users", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Username = table.Column(type: "TEXT", nullable: true), - FirstName = table.Column(type: "TEXT", nullable: true), - LastName = table.Column(type: "TEXT", nullable: true), - LanguageCode = table.Column(type: "TEXT", nullable: true), - IsPremium = table.Column(type: "INTEGER", nullable: true), - HasBotInAttachmentMenu = table.Column(type: "INTEGER", nullable: true), - FirstInteractionAt = table.Column(type: "TEXT", nullable: false), - Discriminator = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Users", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "Conversations", - columns: table => new - { - UserId = table.Column(type: "INTEGER", nullable: false), - ChatId = table.Column(type: "INTEGER", nullable: false), - FirstInteractionAt = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Conversations", x => new { x.ChatId, x.UserId }); - table.ForeignKey( - name: "FK_Conversations_Chats_ChatId", - column: x => x.ChatId, - principalTable: "Chats", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Conversations_Users_UserId", - column: x => x.UserId, - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_Conversations_UserId", - table: "Conversations", - column: "UserId"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Conversations"); - - migrationBuilder.DropTable( - name: "User"); - - migrationBuilder.DropTable( - name: "Chats"); - - migrationBuilder.DropTable( - name: "Users"); - } - } -} diff --git a/src/Sample.Store/Migrations/NavigatorDbContextModelSnapshot.cs b/src/Sample.Store/Migrations/NavigatorDbContextModelSnapshot.cs deleted file mode 100644 index b36c670..0000000 --- a/src/Sample.Store/Migrations/NavigatorDbContextModelSnapshot.cs +++ /dev/null @@ -1,193 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Navigator.Extensions.Store.Context; - -#nullable disable - -namespace Sample.Store.Migrations -{ - [DbContext(typeof(NavigatorDbContext))] - partial class NavigatorDbContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "7.0.11"); - - modelBuilder.Entity("Navigator.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Discriminator") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("FirstName") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("HasBotInAttachmentMenu") - .HasColumnType("INTEGER"); - - b.Property("IsPremium") - .HasColumnType("INTEGER"); - - b.Property("LanguageCode") - .HasColumnType("TEXT"); - - b.Property("LastName") - .HasColumnType("TEXT"); - - b.Property("Username") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("User"); - - b.HasDiscriminator("Discriminator").HasValue("User"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("Navigator.Extensions.Store.Entities.Chat", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("FirstInteractionAt") - .HasColumnType("TEXT"); - - b.Property("IsForum") - .HasColumnType("INTEGER"); - - b.Property("Title") - .HasColumnType("TEXT"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("Chats"); - }); - - modelBuilder.Entity("Navigator.Extensions.Store.Entities.Conversation", b => - { - b.Property("ChatId") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("INTEGER"); - - b.Property("FirstInteractionAt") - .HasColumnType("TEXT"); - - b.HasKey("ChatId", "UserId"); - - b.HasIndex("UserId"); - - b.ToTable("Conversations"); - }); - - modelBuilder.Entity("Navigator.Extensions.Store.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Discriminator") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("FirstInteractionAt") - .HasColumnType("TEXT"); - - b.Property("FirstName") - .HasColumnType("TEXT"); - - b.Property("HasBotInAttachmentMenu") - .HasColumnType("INTEGER"); - - b.Property("IsPremium") - .HasColumnType("INTEGER"); - - b.Property("LanguageCode") - .HasColumnType("TEXT"); - - b.Property("LastName") - .HasColumnType("TEXT"); - - b.Property("Username") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("Users"); - - b.HasDiscriminator("Discriminator").HasValue("User"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("Navigator.Entities.Bot", b => - { - b.HasBaseType("Navigator.Entities.User"); - - b.Property("CanJoinGroups") - .HasColumnType("INTEGER"); - - b.Property("CanReadAllGroupMessages") - .HasColumnType("INTEGER"); - - b.Property("SupportsInlineQueries") - .HasColumnType("INTEGER"); - - b.HasDiscriminator().HasValue("Bot"); - }); - - modelBuilder.Entity("Navigator.Extensions.Store.Entities.Bot", b => - { - b.HasBaseType("Navigator.Extensions.Store.Entities.User"); - - b.HasDiscriminator().HasValue("Bot"); - }); - - modelBuilder.Entity("Navigator.Extensions.Store.Entities.Conversation", b => - { - b.HasOne("Navigator.Extensions.Store.Entities.Chat", "Chat") - .WithMany("Conversations") - .HasForeignKey("ChatId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Navigator.Extensions.Store.Entities.User", "User") - .WithMany("Conversations") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chat"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Navigator.Extensions.Store.Entities.Chat", b => - { - b.Navigation("Conversations"); - }); - - modelBuilder.Entity("Navigator.Extensions.Store.Entities.User", b => - { - b.Navigation("Conversations"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/Sample.Store/Program.cs b/src/Sample.Store/Program.cs deleted file mode 100644 index 74c40e5..0000000 --- a/src/Sample.Store/Program.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using Incremental.Common.Configuration; -using Microsoft.AspNetCore.Builder; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Navigator; -using Navigator.Configuration; -using Navigator.Extensions.Store; -using Navigator.Extensions.Store.Context; - -namespace Sample.Store; - -public class Program -{ - public static void Main(string[] args) - { - var builder = WebApplication.CreateBuilder(args); - - builder.Configuration.AddCommonConfiguration(); - - builder.Services.AddMemoryCache(); - - builder.Services.AddNavigator(options => - { - options.SetWebHookBaseUrl(builder.Configuration["BASE_WEBHOOK_URL"]!); - options.RegisterActionsFromAssemblies(AppDomain.CurrentDomain.GetAssemblies()); - options.SetTelegramToken(builder.Configuration["TELEGRAM_TOKEN"]!); - }).WithExtension.Store(optionsBuilder => - { - optionsBuilder.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection"), - b => b.MigrationsAssembly("Sample.Store")); - }); - - var app = builder.Build(); - - using var serviceScope = app.Services.GetService()?.CreateScope(); - serviceScope?.ServiceProvider.GetRequiredService().Database.Migrate(); - - app.MapNavigator(); - - app.Run(); - } -} \ No newline at end of file diff --git a/src/Sample.Store/Sample.Store.csproj b/src/Sample.Store/Sample.Store.csproj deleted file mode 100644 index 0921fe8..0000000 --- a/src/Sample.Store/Sample.Store.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - net7.0 - enable - false - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - diff --git a/src/Sample.Store/app.db-shm b/src/Sample.Store/app.db-shm deleted file mode 100644 index fe9ac2845eca6fe6da8a63cd096d9cf9e24ece10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeIuAr62r3 - - - net7.0 - enable - enable - - false - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - diff --git a/src/Sample.Testing/TestFactory.cs b/src/Sample.Testing/TestFactory.cs deleted file mode 100644 index 73f1621..0000000 --- a/src/Sample.Testing/TestFactory.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.AspNetCore.TestHost; -using Xunit; - -namespace Sample.Testing; - -public class TestFactory : WebApplicationFactory, IAsyncLifetime - where TProgram : class -{ - protected override void ConfigureWebHost(IWebHostBuilder builder) - { - builder.ConfigureTestServices(services => - { - }); - } - - public Task InitializeAsync() - { - return Task.CompletedTask; - } - - public new Task DisposeAsync() - { - return Task.CompletedTask; - } -} \ No newline at end of file From 36ac26b935671650227aac640948dca2d4d126dd Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 16:05:36 +0200 Subject: [PATCH 61/66] feat: add some logs to NavigatorStrategy --- src/Navigator/Actions/BotActionInformation.cs | 10 ++++++- src/Navigator/Strategy/NavigatorStrategy.cs | 28 ++++++++++++++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/Navigator/Actions/BotActionInformation.cs b/src/Navigator/Actions/BotActionInformation.cs index a498a67..17970b1 100644 --- a/src/Navigator/Actions/BotActionInformation.cs +++ b/src/Navigator/Actions/BotActionInformation.cs @@ -4,9 +4,9 @@ public record BotActionInformation { public required UpdateCategory Category; public required Type[] ConditionInputTypes; + public required TimeSpan? Cooldown; public required Type[] HandlerInputTypes; public required ushort Priority; - public required TimeSpan? Cooldown; } public sealed record UpdateCategory(string Kind, string? Subkind = default) @@ -22,4 +22,12 @@ public override int GetHashCode() { return HashCode.Combine(Kind, Subkind); } + + /// + public override string ToString() + { + return Subkind is null + ? Kind + : $"{Kind}.{Subkind}"; + } } \ No newline at end of file diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index 774b484..293ed96 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Navigator.Actions; using Navigator.Catalog; using Navigator.Catalog.Factory; @@ -25,6 +26,7 @@ public class NavigatorStrategy : INavigatorStrategy private readonly IMemoryCache _cache; private readonly BotActionCatalog _catalog; private readonly IUpdateClassifier _classifier; + private readonly ILogger _logger; private readonly INavigatorOptions _options; private readonly IServiceProvider _serviceProvider; @@ -36,14 +38,16 @@ public class NavigatorStrategy : INavigatorStrategy /// The instance. /// The instance. /// The instance. + /// The instance. public NavigatorStrategy(IMemoryCache cache, BotActionCatalogFactory catalogFactory, IUpdateClassifier classifier, - INavigatorOptions options, IServiceProvider serviceProvider) + INavigatorOptions options, IServiceProvider serviceProvider, ILogger logger) { _cache = cache; _catalog = catalogFactory.Retrieve(); _classifier = classifier; _options = options; _serviceProvider = serviceProvider; + _logger = logger; } /// @@ -55,16 +59,32 @@ public NavigatorStrategy(IMemoryCache cache, BotActionCatalogFactory catalogFact /// The object to be processed. public async Task Invoke(Update update) { + _logger.LogInformation("Processing update {UpdateId}", update.Id); + if (_options.TypingNotificationIsEnabled() && update.GetChatOrDefault() is { } chat) + { + _logger.LogInformation("Sending typing notification to chat {ChatId}", chat.Id); + await _serviceProvider.GetRequiredService().SendChatActionAsync(chat, ChatAction.Typing); + } + + var updateCategory = await _classifier.Process(update); - var actionType = await _classifier.Process(update); + _logger.LogInformation("Update {UpdateId} classified as {UpdateCategory}", update.Id, + updateCategory); - var relevantActions = _catalog.Retrieve(actionType); + var relevantActions = _catalog.Retrieve(updateCategory); + + _logger.LogInformation("Found {RelevantActionsCount} relevant actions for {UpdateId}", relevantActions.Count(), update.Id); relevantActions = relevantActions.Where(action => IsNotInCooldown(action, update)); - await foreach (var action in FilterActionsThatCanHandleUpdate(relevantActions, update)) await ExecuteAction(action, update); + await foreach (var action in FilterActionsThatCanHandleUpdate(relevantActions, update)) + { + _logger.LogInformation("Executing action {ActionId}", action.Id); + + await ExecuteAction(action, update); + } } /// From 832f53dcc4be00be19a01b8880cc6263da8fa625 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 16:21:41 +0200 Subject: [PATCH 62/66] feat: delete unnecessary dependencies --- src/Navigator/Navigator.csproj | 14 +++++--------- src/Navigator/Strategy/NavigatorStrategy.cs | 7 +++---- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/Navigator/Navigator.csproj b/src/Navigator/Navigator.csproj index a898fe2..905d10b 100644 --- a/src/Navigator/Navigator.csproj +++ b/src/Navigator/Navigator.csproj @@ -17,21 +17,17 @@ AGPL-3.0-only Copyright © Lucas Maximiliano Marino 2023 - + - + - + - + - - - - - + diff --git a/src/Navigator/Strategy/NavigatorStrategy.cs b/src/Navigator/Strategy/NavigatorStrategy.cs index 293ed96..d6f67c3 100644 --- a/src/Navigator/Strategy/NavigatorStrategy.cs +++ b/src/Navigator/Strategy/NavigatorStrategy.cs @@ -51,10 +51,9 @@ public NavigatorStrategy(IMemoryCache cache, BotActionCatalogFactory catalogFact } /// - /// Processes an by determining the appropriate action type, - /// retrieving relevant from the , - /// filtering those actions based on the , - /// and executing each filtered action asynchronously. + /// Processes an by determining the appropriate action type, retrieving relevant from + /// the, filtering those actions based on the , executing each filtered action + /// asynchronously. /// /// The object to be processed. public async Task Invoke(Update update) From f948facd63a76b8652a011596057b3e8b1ef2374 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 16:21:51 +0200 Subject: [PATCH 63/66] chore: update sample and README.md --- README.md | 141 ++++++++++++------------------------------ src/Sample/Program.cs | 22 +++++-- 2 files changed, 58 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index cd8be2f..9ea3a5d 100644 --- a/README.md +++ b/README.md @@ -1,122 +1,63 @@ # Navigator + A highly opinionated telegram bot framework, mainly based on [Telegram.Bot](https://github.com/TelegramBots/Telegram.Bot). -This framework relies heavily in [MediatR](https://github.com/jbogard/MediatR) and it is shaped accordingly. +The only requirement is `Microsoft.AspNetCore.App (>= 8.0)`. -The base package ([Navigator](https://www.nuget.org/packages/Navigator/)) it's usable on it's own but the [Actions](https://www.nuget.org/packages/Navigator.Extensions.Actions) extension it's highly encouraged as it brings default implementations for almost every type of incoming telegram update, in the future we may merge it into the base package. +The usage is very simple yet powerful: -For storage of users, chats and conversations the [Store](https://www.nuget.org/packages/Navigator.Extensions.Store) extension works really well with Navigator, it automatically recognizes users and groups, saves them to the database for future use and injects into the NavigatorContext all the data you may have about a user or a chat, you can also use your own models and it will still work, check out the examples for more information. +```csharp +... +using Navigator; +... -Finally the [Shipyard](https://www.nuget.org/packages/Navigator.Extensions.Shipyard) WIP package gives you an useful API to retrieve information about your bot, change some of it's configuration and launch some actions. A companion web-based UI is also planned. +var builder = WebApplication.CreateBuilder(args); -## Packages +builder.Services.AddMemoryCache(); -| Package | Last Stable | Last Prerelease | -|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Navigator | [![package.nav](https://img.shields.io/nuget/v/Navigator?style=flat-square)](https://www.nuget.org/packages/Navigator/) | [![package.nav.pre](https://img.shields.io/nuget/vpre/Navigator?style=flat-square)](https://www.nuget.org/packages/Navigator/) | -| Navigator.Extensions.Actions | [![package.nav.ext.act](https://img.shields.io/nuget/v/Navigator.Extensions.Actions?style=flat-square)](https://www.nuget.org/packages/Navigator.Extensions.Actions) | [![package.nav.ext.act.pre](https://img.shields.io/nuget/vpre/Navigator.Extensions.Actions?style=flat-square)](https://www.nuget.org/packages/Navigator.Extensions.Actions) | -| Navigator.Extensions.Store | [![package.nav.ext.sto](https://img.shields.io/nuget/v/Navigator.Extensions.Actions?style=flat-square)](https://www.nuget.org/packages/Navigator.Extensions.Store) | [![package.nav.ext.sto.pre](https://img.shields.io/nuget/vpre/Navigator.Extensions.Store?style=flat-square)](https://www.nuget.org/packages/Navigator.Extensions.Store) | -| Navigator.Extensions.Shipyard | [![package.nav.ext.ship](https://img.shields.io/nuget/v/Navigator.Extensions.Shipyard?style=flat-square)](https://www.nuget.org/packages/Navigator.Extensions.Shipyard) | [![package.nav.ext.ship.pre](https://img.shields.io/nuget/vpre/Navigator.Extensions.Shipyard?style=flat-square)](https://www.nuget.org/packages/Navigator.Extensions.Shipyard) | +builder.Services.AddNavigator(options => +{ + options.SetWebHookBaseUrl(builder.Configuration["BASE_WEBHOOK_URL"]!); + options.SetTelegramToken(builder.Configuration["TELEGRAM_TOKEN"]!); + options.EnableTypingNotification(); +}); -# Requirements -- ASP.NET (>= net5.0) -- MediatR (>= 9.0.0) +var app = builder.Build(); -# Examples -Some examples can be found in the [samples](https://github.com/navigatorframework/navigator/src/) repository. +var bot = app.GetBot(); -Also checkout some bots made with `Navigator`: -- [@ThankiesBot](https://t.me/thankiesbot), check out it's [source code](https://github.com/elementh/thankies). -- [@FOSCBot](https://t.me/foscbot), check out it's [source code](https://github.com/elementh/foscbot). +// This action will be triggered if the user sends a message in the style of `/join `. +bot.OnCommand("join", async (INavigatorClient client, Chat chat, string[] parameters) => +{ + var result = string.Join(',', parameters); -# Basic Usage -## Configuration -Including Navigator in your project is simple: + await client.SendTextMessageAsync(chat, result); +}); -```csharp -public class Startup -{ - // ... - - public void ConfigureServices(IServiceCollection services) - { - // ... - services.AddControllers().AddNewtonsoftJson(); - - services.AddMediatR(typeof(Startup).Assembly); // And any other assembly that may be needed. - - services.AddNavigator(options => - { - options.SetTelegramToken(Configuration["BOT_TOKEN"]); // Your telegram bot token. - options.SetWebHookBaseUrl(Configuration["BASE_WEBHOOK_URL"]); // The base url where you are going to receive the updates from teelgram. - options.RegisterActionsFromAssemblies(typeof(Startup).Assembly); // All your actions. - }); - - /// ... - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - /// ... - - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - endpoints.MapNavigator(); // In order to receive updates from telegram. - }); - - /// ... - } -} +app.MapNavigator(); + +app.Run(); ``` -More options are available, check out the wiki. +## Packages -## Bot Actions -Example of a basic echo action using the base package + the actions extension. +| Package | Last Stable | Last Prerelease | +|-----------|-------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------| +| Navigator | [![package.nav](https://img.shields.io/nuget/v/Navigator?style=flat-square)](https://www.nuget.org/packages/Navigator/) | [![package.nav.pre](https://img.shields.io/nuget/vpre/Navigator?style=flat-square)](https://www.nuget.org/packages/Navigator/) | -```csharp -public class EchoAction : MessageAction -{ - public string MessageToEcho { get; set; } = string.Empty; - - public override IAction Init(INavigatorContext ctx) - { - if (string.IsNullOrWhiteSpace(ctx.Update.Message.Text)) - { - MessageToEcho = ctx.Update.Message.Text; - } - return this; - } - - public override bool CanHandle(INavigatorContext ctx) - { - return !string.IsNullOrWhiteSpace(MessageToEcho); - } -} - -/// ... - -public class EchoActionHandler : ActionHandler -{ - public EchoActionHandler(INavigatorContext ctx) : base(ctx) - { - } - - public override async Task Handle(EchoAction request, CancellationToken cancellationToken) - { - await Ctx.Client.SendTextMessageAsync(Ctx.GetTelegramChat(), request.MessageToEcho, - cancellationToken: cancellationToken); - - return Unit.Value; - } -} -``` +# Examples +Some examples can be found in the [samples](https://github.com/navigatorframework/navigator/src/) repository. + +Also checkout some bots made with `Navigator`: + +- [@ThankiesBot](https://t.me/thankiesbot), check out it's [source code](https://github.com/elementh/thankies). +- [@FOSCBot](https://t.me/foscbot), check out it's [source code](https://github.com/elementh/foscbot). # License + Navigator Framework -Copyright (C) 2019-2021 Lucas Maximiliano Marino +Copyright (C) 2019-2024 Lucas Maximiliano Marino This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -125,8 +66,8 @@ by the Free Software Foundation, either version 3 of the License, or This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . \ No newline at end of file +along with this program. If not, see . \ No newline at end of file diff --git a/src/Sample/Program.cs b/src/Sample/Program.cs index 266a493..4262871 100644 --- a/src/Sample/Program.cs +++ b/src/Sample/Program.cs @@ -1,5 +1,7 @@ +using System; using Incremental.Common.Configuration; using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; using Navigator; using Navigator.Catalog.Factory.Extensions; using Navigator.Client; @@ -13,6 +15,8 @@ builder.Configuration.AddCommonConfiguration(); +builder.Services.AddMemoryCache(); + builder.Services.AddNavigator(options => { options.SetWebHookBaseUrl(builder.Configuration["BASE_WEBHOOK_URL"]!); @@ -36,11 +40,19 @@ // This action will be triggered for every message sent to the chat. Additionally in this code example, this action will be triggered // only if NavigatorOptions.MultipleActionsUSageIsEnabled is set to true. bot.OnMessage((Update _) => true, async (INavigatorClient client, Chat chat, Message message) => -{ - var text = $"message received: {message.MessageId}"; - - await client.SendTextMessageAsync(chat, text); -}); + { + var text = $"message received: {message.MessageId}"; + + await client.SendTextMessageAsync(chat, text); + }) + .WithCooldown(TimeSpan.FromSeconds(30)); + +// This action will be triggered if the user sends a message in the style of `/sad`. +bot.OnCommand("sad", + async (INavigatorClient client, Chat chat) => + { + await client.SendStickerAsync(chat, "CAACAgQAAxkBAAI5DF59uqkJYnqzc5LcnEC_bdp0rerIAAJsAwACmOejAAG_qYNUT_L_exgE"); + }); app.MapNavigator(); From 04f8ff15a1a05ff9215757b9a079a1f1b38c173d Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 16:53:45 +0200 Subject: [PATCH 64/66] docs: improve all documentation of public members --- src/Navigator/Actions/BotAction.cs | 50 +++++- src/Navigator/Actions/BotActionInformation.cs | 27 +++ .../Actions/Builder/BotActionBuilder.cs | 50 ++++-- src/Navigator/Catalog/BotActionCatalog.cs | 36 ++-- .../Factory/BotActionCatalogFactory.cs | 22 ++- .../BotActionCatalogFactoryExtensions.cs | 156 +++++++++--------- src/Navigator/Strategy/INavigatorStrategy.cs | 8 + .../TypeProvider/IArgumentTypeProvider.cs | 13 ++ 8 files changed, 255 insertions(+), 107 deletions(-) diff --git a/src/Navigator/Actions/BotAction.cs b/src/Navigator/Actions/BotAction.cs index 3b73153..327733b 100644 --- a/src/Navigator/Actions/BotAction.cs +++ b/src/Navigator/Actions/BotAction.cs @@ -1,24 +1,54 @@ namespace Navigator.Actions; +/// +/// A is a representation of an action that can be executed by a navigator bot. It is used to encapsulate a +/// condition and a handler. The condition is a delegate that is checked at runtime and if it evaluates to true, the handler is executed. +/// The condition delegate should return a boolean or a Task that resolves to a boolean. The handler delegate should return void or a Task +/// that resolves to void. +/// public sealed record BotAction { - private readonly Delegate Condition; - private readonly Delegate Handler; + private readonly Delegate _condition; + private readonly Delegate _handler; + + /// + /// The id of the . + /// public readonly Guid Id; + + /// + /// The information about the . + /// public readonly BotActionInformation Information; + /// + /// Initializes a new instance of the class. + /// + /// The id of the . + /// The information about the . + /// The condition delegate. + /// The handler delegate. public BotAction(Guid id, BotActionInformation information, Delegate condition, Delegate handler) { Id = id; Information = information; - Condition = condition; - Handler = handler; + _condition = condition; + _handler = handler; } + /// + /// Executes the condition of the . + /// + /// + /// The arguments that are passed to the condition delegate. + /// + /// + /// A boolean that indicates if the condition is true, and therefore the handler should be executed. + /// + /// When the condition delegate returns a something that is not a Task or a boolean. public async Task ExecuteCondition(object?[] args) { - // var result = Condition.DynamicInvoke(args.First()); - var result = Condition.Method.Invoke(Condition.Target, args); + var result = _condition.Method.Invoke(_condition.Target, args); return result switch { @@ -29,9 +59,15 @@ public async Task ExecuteCondition(object?[] args) }; } + /// + /// Executes the handler of the . + /// + /// + /// The arguments that are passed to the handler delegate. + /// public async Task ExecuteHandler(object?[] args) { - var result = Handler.Method.Invoke(Handler.Target, args); + var result = _handler.Method.Invoke(_handler.Target, args); if (result is Task task) await task; } diff --git a/src/Navigator/Actions/BotActionInformation.cs b/src/Navigator/Actions/BotActionInformation.cs index 17970b1..2fcd141 100644 --- a/src/Navigator/Actions/BotActionInformation.cs +++ b/src/Navigator/Actions/BotActionInformation.cs @@ -1,14 +1,41 @@ namespace Navigator.Actions; +/// +/// Information about a . +/// public record BotActionInformation { + /// + /// The of the . + /// public required UpdateCategory Category; + + /// + /// The input types of the condition delegate of the . + /// public required Type[] ConditionInputTypes; + + /// + /// The cooldown of the . Optional. + /// public required TimeSpan? Cooldown; + + /// + /// The input types of the handler delegate of the . + /// public required Type[] HandlerInputTypes; + + /// + /// The priority of the . Optional. + /// public required ushort Priority; } +/// +/// The of the to which the action belongs. +/// +/// A string that represents the kind of the . +/// A string that represents the subkind of the . public sealed record UpdateCategory(string Kind, string? Subkind = default) { /// diff --git a/src/Navigator/Actions/Builder/BotActionBuilder.cs b/src/Navigator/Actions/Builder/BotActionBuilder.cs index d3ccbc6..597afd8 100644 --- a/src/Navigator/Actions/Builder/BotActionBuilder.cs +++ b/src/Navigator/Actions/Builder/BotActionBuilder.cs @@ -1,5 +1,8 @@ namespace Navigator.Actions.Builder; +/// +/// Builder for . +/// public class BotActionBuilder { private readonly Delegate _condition; @@ -8,6 +11,16 @@ public class BotActionBuilder private readonly Type[] _handlerInputTypes; private readonly Guid _id; + /// + /// Initializes a new instance of the class. + /// + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is . + /// + /// + /// A delegate representing the action to take when the condition is met. + /// public BotActionBuilder(Delegate condition, Delegate handler) { _id = Guid.NewGuid(); @@ -19,12 +32,12 @@ public BotActionBuilder(Delegate condition, Delegate handler) _conditionInputTypes = condition.Method.GetParameters().Select(info => info.ParameterType).ToArray(); _handler = handler; _handlerInputTypes = handler.Method.GetParameters().Select(info => info.ParameterType).ToArray(); - _priority = Priority.Default; + Priority = Actions.Priority.Default; } - private UpdateCategory _category { get; set; } - private ushort _priority { get; set; } - private TimeSpan? _cooldown { get; set; } + private UpdateCategory Category { get; set; } = null!; + private ushort Priority { get; set; } + private TimeSpan? Cooldown { get; set; } /// /// Builds the bot action. @@ -34,31 +47,46 @@ public BotAction Build() { var information = new BotActionInformation { - Category = _category, + Category = Category, ConditionInputTypes = _conditionInputTypes, HandlerInputTypes = _handlerInputTypes, - Priority = _priority, - Cooldown = _cooldown + Priority = Priority, + Cooldown = Cooldown }; return new BotAction(_id, information, _condition, _handler); } + /// + /// Sets the priority of the . + /// + /// The priority to be set. + /// An instance of to be able to continue configuring the . public BotActionBuilder WithPriority(ushort priority) { - _priority = priority; + Priority = priority; return this; } + /// + /// Sets the cooldown of the . + /// + /// The cooldown to be set. + /// An instance of to be able to continue configuring the . public BotActionBuilder WithCooldown(TimeSpan cooldown) { - _cooldown = cooldown; + Cooldown = cooldown; return this; } - public BotActionBuilder SetType(UpdateCategory category) + /// + /// Sets the of the . + /// + /// The to be set. + /// An instance of to be able to continue configuring the . + public BotActionBuilder SetCategory(UpdateCategory category) { - _category = category; + Category = category; return this; } } \ No newline at end of file diff --git a/src/Navigator/Catalog/BotActionCatalog.cs b/src/Navigator/Catalog/BotActionCatalog.cs index e0193be..16eabf9 100644 --- a/src/Navigator/Catalog/BotActionCatalog.cs +++ b/src/Navigator/Catalog/BotActionCatalog.cs @@ -1,23 +1,39 @@ using Navigator.Actions; +using Telegram.Bot.Types; namespace Navigator.Catalog; -public record BotActionCatalog +/// +/// Represents a catalog of instances. The catalog is used to efficiently retrieve +/// instances based on their and . The catalog also +/// provides a way to prioritize instances, which is useful when multiple instances +/// can potentially handle the same . +/// +public sealed record BotActionCatalog { - protected readonly Dictionary Actions; - protected readonly Dictionary PriorityByAction; - + private readonly Dictionary _actions; + private readonly Dictionary _priorityByAction; + + /// + /// Initializes a new instance of the class. + /// + /// The list of instances. public BotActionCatalog(IList actions) { - Actions = actions.ToDictionary(action => action.Id); - PriorityByAction = actions.ToDictionary(action => action.Id, action => action.Information.Priority); + _actions = actions.ToDictionary(action => action.Id); + _priorityByAction = actions.ToDictionary(action => action.Id, action => action.Information.Priority); } - - //TODO: rework this into IAsyncEnumerable and yield + + /// + /// Retrieves all instances with the specified , + /// ordered by their priority. + /// + /// The of the instances to retrieve. + /// A list of instances. public IEnumerable Retrieve(UpdateCategory category) { - return Actions.Values + return _actions.Values .Where(action => action.Information.Category == category) - .OrderBy(action => PriorityByAction[action.Id]); + .OrderBy(action => _priorityByAction[action.Id]); } } \ No newline at end of file diff --git a/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs b/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs index e03b092..59ba6d2 100644 --- a/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs +++ b/src/Navigator/Catalog/Factory/BotActionCatalogFactory.cs @@ -4,23 +4,40 @@ namespace Navigator.Catalog.Factory; +/// +/// Factory for . +/// public class BotActionCatalogFactory { private List Actions { get; } = []; private BotActionCatalog? Catalog { get; set; } + /// + /// Adds a new to the catalog. + /// + /// + /// A delegate representing the condition under which the handler should be invoked. + /// Must return or where TResult is . + /// + /// + /// A delegate representing the action to take when the condition is met. + /// public BotActionBuilder OnUpdate(Delegate condition, Delegate handler) { var id = Guid.NewGuid(); var actionBuilder = new BotActionBuilder(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Unknown))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Unknown))); Actions.Add(actionBuilder); return actionBuilder; } + /// + /// Retrieves the built . + /// + /// The built . public BotActionCatalog Retrieve() { if (Catalog is null) Build(); @@ -28,6 +45,9 @@ public BotActionCatalog Retrieve() return Catalog!; } + /// + /// Builds the . + /// private void Build() { var actions = Actions diff --git a/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs b/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs index 207669e..2e5cfa2 100644 --- a/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs +++ b/src/Navigator/Catalog/Factory/Extensions/BotActionCatalogFactoryExtensions.cs @@ -71,7 +71,7 @@ public static BotActionBuilder OnCommand(this BotActionCatalogFactory factory, s { var actionBuilder = factory.OnUpdate((Update update) => update.Message?.ExtractCommand() == command, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageEntityType.BotCommand))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageEntityType.BotCommand))); return actionBuilder; } @@ -96,7 +96,7 @@ public static BotActionBuilder OnMessage(this BotActionCatalogFactory factory, D { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType))); return actionBuilder; } @@ -120,7 +120,7 @@ public static BotActionBuilder OnText(this BotActionCatalogFactory factory, Dele { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Text))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Text))); return actionBuilder; } @@ -144,7 +144,7 @@ public static BotActionBuilder OnPhoto(this BotActionCatalogFactory factory, Del { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Photo))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Photo))); return actionBuilder; } @@ -168,7 +168,7 @@ public static BotActionBuilder OnAudio(this BotActionCatalogFactory factory, Del { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Audio))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Audio))); return actionBuilder; } @@ -192,7 +192,7 @@ public static BotActionBuilder OnVideo(this BotActionCatalogFactory factory, Del { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Video))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Video))); return actionBuilder; } @@ -216,7 +216,7 @@ public static BotActionBuilder OnVoice(this BotActionCatalogFactory factory, Del { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Voice))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Voice))); return actionBuilder; } @@ -240,7 +240,7 @@ public static BotActionBuilder OnDocument(this BotActionCatalogFactory factory, { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Document))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Document))); return actionBuilder; } @@ -264,7 +264,7 @@ public static BotActionBuilder OnSticker(this BotActionCatalogFactory factory, D { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Sticker))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Sticker))); return actionBuilder; } @@ -288,7 +288,7 @@ public static BotActionBuilder OnLocation(this BotActionCatalogFactory factory, { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Location))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Location))); return actionBuilder; } @@ -312,7 +312,7 @@ public static BotActionBuilder OnContact(this BotActionCatalogFactory factory, D { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Contact))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Contact))); return actionBuilder; } @@ -336,7 +336,7 @@ public static BotActionBuilder OnVenue(this BotActionCatalogFactory factory, Del { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Venue))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Venue))); return actionBuilder; } @@ -360,7 +360,7 @@ public static BotActionBuilder OnGame(this BotActionCatalogFactory factory, Dele { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Game))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Game))); return actionBuilder; } @@ -384,7 +384,7 @@ public static BotActionBuilder OnVideoNote(this BotActionCatalogFactory factory, { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoNote))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoNote))); return actionBuilder; } @@ -408,7 +408,7 @@ public static BotActionBuilder OnInvoice(this BotActionCatalogFactory factory, D { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Invoice))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Invoice))); return actionBuilder; } @@ -432,7 +432,7 @@ public static BotActionBuilder OnSuccessfulPayment(this BotActionCatalogFactory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.SuccessfulPayment))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.SuccessfulPayment))); return actionBuilder; } @@ -456,7 +456,7 @@ public static BotActionBuilder OnConnectedWebsite(this BotActionCatalogFactory f { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ConnectedWebsite))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.ConnectedWebsite))); return actionBuilder; } @@ -480,7 +480,7 @@ public static BotActionBuilder OnNewChatMembers(this BotActionCatalogFactory fac { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatMembers))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatMembers))); return actionBuilder; } @@ -504,7 +504,7 @@ public static BotActionBuilder OnLeftChatMember(this BotActionCatalogFactory fac { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.LeftChatMember))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.LeftChatMember))); return actionBuilder; } @@ -528,7 +528,7 @@ public static BotActionBuilder OnNewChatTitle(this BotActionCatalogFactory facto { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatTitle))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatTitle))); return actionBuilder; } @@ -552,7 +552,7 @@ public static BotActionBuilder OnNewChatPhoto(this BotActionCatalogFactory facto { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatPhoto))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.NewChatPhoto))); return actionBuilder; } @@ -576,7 +576,7 @@ public static BotActionBuilder OnPinnedMessage(this BotActionCatalogFactory fact { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.PinnedMessage))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.PinnedMessage))); return actionBuilder; } @@ -600,7 +600,7 @@ public static BotActionBuilder OnDeleteChatPhoto(this BotActionCatalogFactory fa { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.DeleteChatPhoto))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.DeleteChatPhoto))); return actionBuilder; } @@ -624,7 +624,7 @@ public static BotActionBuilder OnGroupChatCreated(this BotActionCatalogFactory f { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.GroupChatCreated))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.GroupChatCreated))); return actionBuilder; } @@ -649,7 +649,7 @@ public static BotActionBuilder OnSupergroupChatCreated(this BotActionCatalogFact { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.SupergroupChatCreated))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.SupergroupChatCreated))); return actionBuilder; } @@ -673,7 +673,7 @@ public static BotActionBuilder OnChannelChatCreated(this BotActionCatalogFactory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ChannelChatCreated))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.ChannelChatCreated))); return actionBuilder; } @@ -697,7 +697,7 @@ public static BotActionBuilder OnMigrateFromChatId(this BotActionCatalogFactory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.MigrateFromChatId))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.MigrateFromChatId))); return actionBuilder; } @@ -721,7 +721,7 @@ public static BotActionBuilder OnMigrateToChatId(this BotActionCatalogFactory fa { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.MigrateToChatId))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.MigrateToChatId))); return actionBuilder; } @@ -745,7 +745,7 @@ public static BotActionBuilder OnPollMessage(this BotActionCatalogFactory factor { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Poll))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Poll))); return actionBuilder; } @@ -769,7 +769,7 @@ public static BotActionBuilder OnDice(this BotActionCatalogFactory factory, Dele { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Dice))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Dice))); return actionBuilder; } @@ -795,7 +795,7 @@ public static BotActionBuilder OnMessageAutoDeleteTimerChanged(this BotActionCat { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.MessageAutoDeleteTimerChanged))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.MessageAutoDeleteTimerChanged))); return actionBuilder; } @@ -820,7 +820,7 @@ public static BotActionBuilder OnProximityAlertTriggered(this BotActionCatalogFa { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ProximityAlertTriggered))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.ProximityAlertTriggered))); return actionBuilder; } @@ -844,7 +844,7 @@ public static BotActionBuilder OnWebAppData(this BotActionCatalogFactory factory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.WebAppData))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.WebAppData))); return actionBuilder; } @@ -868,7 +868,7 @@ public static BotActionBuilder OnVideoChatScheduled(this BotActionCatalogFactory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatScheduled))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatScheduled))); return actionBuilder; } @@ -892,7 +892,7 @@ public static BotActionBuilder OnVideoChatStarted(this BotActionCatalogFactory f { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatStarted))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatStarted))); return actionBuilder; } @@ -916,7 +916,7 @@ public static BotActionBuilder OnVideoChatEnded(this BotActionCatalogFactory fac { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatEnded))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatEnded))); return actionBuilder; } @@ -942,7 +942,7 @@ public static BotActionBuilder OnVideoChatParticipantsInvited(this BotActionCata { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatParticipantsInvited))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.VideoChatParticipantsInvited))); return actionBuilder; } @@ -966,7 +966,7 @@ public static BotActionBuilder OnAnimation(this BotActionCatalogFactory factory, { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Animation))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Animation))); return actionBuilder; } @@ -990,7 +990,7 @@ public static BotActionBuilder OnForumTopicCreated(this BotActionCatalogFactory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicCreated))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicCreated))); return actionBuilder; } @@ -1014,7 +1014,7 @@ public static BotActionBuilder OnForumTopicClosed(this BotActionCatalogFactory f { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicClosed))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicClosed))); return actionBuilder; } @@ -1038,7 +1038,7 @@ public static BotActionBuilder OnForumTopicReopened(this BotActionCatalogFactory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicReopened))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicReopened))); return actionBuilder; } @@ -1062,7 +1062,7 @@ public static BotActionBuilder OnForumTopicEdited(this BotActionCatalogFactory f { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicEdited))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.ForumTopicEdited))); return actionBuilder; } @@ -1086,7 +1086,7 @@ public static BotActionBuilder OnGeneralForumTopicHidden(this BotActionCatalogFa { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.GeneralForumTopicHidden))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.GeneralForumTopicHidden))); return actionBuilder; } @@ -1110,7 +1110,7 @@ public static BotActionBuilder OnGeneralForumTopicUnhidden(this BotActionCatalog { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.GeneralForumTopicUnhidden))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.GeneralForumTopicUnhidden))); return actionBuilder; } @@ -1134,7 +1134,7 @@ public static BotActionBuilder OnWriteAccessAllowed(this BotActionCatalogFactory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.WriteAccessAllowed))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.WriteAccessAllowed))); return actionBuilder; } @@ -1158,7 +1158,7 @@ public static BotActionBuilder OnUsersShared(this BotActionCatalogFactory factor { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.UsersShared))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.UsersShared))); return actionBuilder; } @@ -1182,7 +1182,7 @@ public static BotActionBuilder OnChatShared(this BotActionCatalogFactory factory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ChatShared))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.ChatShared))); return actionBuilder; } @@ -1206,7 +1206,7 @@ public static BotActionBuilder OnPassportData(this BotActionCatalogFactory facto { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.PassportData))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.PassportData))); return actionBuilder; } @@ -1230,7 +1230,7 @@ public static BotActionBuilder OnGiveawayCreated(this BotActionCatalogFactory fa { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayCreated))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayCreated))); return actionBuilder; } @@ -1254,7 +1254,7 @@ public static BotActionBuilder OnGiveaway(this BotActionCatalogFactory factory, { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Giveaway))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Giveaway))); return actionBuilder; } @@ -1278,7 +1278,7 @@ public static BotActionBuilder OnGiveawayWinners(this BotActionCatalogFactory fa { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayWinners))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayWinners))); return actionBuilder; } @@ -1302,7 +1302,7 @@ public static BotActionBuilder OnGiveawayCompleted(this BotActionCatalogFactory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayCompleted))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.GiveawayCompleted))); return actionBuilder; } @@ -1326,7 +1326,7 @@ public static BotActionBuilder OnBoostAdded(this BotActionCatalogFactory factory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.BoostAdded))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.BoostAdded))); return actionBuilder; } @@ -1350,7 +1350,7 @@ public static BotActionBuilder OnChatBackgroundSet(this BotActionCatalogFactory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.ChatBackgroundSet))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.ChatBackgroundSet))); return actionBuilder; } @@ -1374,7 +1374,7 @@ public static BotActionBuilder OnPaidMedia(this BotActionCatalogFactory factory, { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.PaidMedia))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.PaidMedia))); return actionBuilder; } @@ -1398,7 +1398,7 @@ public static BotActionBuilder OnRefundedPayment(this BotActionCatalogFactory fa { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.RefundedPayment))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.RefundedPayment))); return actionBuilder; } @@ -1422,7 +1422,7 @@ public static BotActionBuilder OnUnknownMessage(this BotActionCatalogFactory fac { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(MessageType), nameof(MessageType.Unknown))); + actionBuilder.SetCategory(new UpdateCategory(nameof(MessageType), nameof(MessageType.Unknown))); return actionBuilder; } @@ -1445,7 +1445,7 @@ public static BotActionBuilder OnInlineQuery(this BotActionCatalogFactory factor { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.InlineQuery))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.InlineQuery))); return actionBuilder; } @@ -1468,7 +1468,7 @@ public static BotActionBuilder OnChosenInlineResult(this BotActionCatalogFactory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChosenInlineResult))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChosenInlineResult))); return actionBuilder; } @@ -1491,7 +1491,7 @@ public static BotActionBuilder OnCallbackQuery(this BotActionCatalogFactory fact { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.CallbackQuery))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.CallbackQuery))); return actionBuilder; } @@ -1515,7 +1515,7 @@ public static BotActionBuilder OnEditedMessage(this BotActionCatalogFactory fact { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedMessage))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedMessage))); return actionBuilder; } @@ -1539,7 +1539,7 @@ public static BotActionBuilder OnEditedChannelPost(this BotActionCatalogFactory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedChannelPost))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedChannelPost))); return actionBuilder; } @@ -1563,7 +1563,7 @@ public static BotActionBuilder OnShippingQuery(this BotActionCatalogFactory fact { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ShippingQuery))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ShippingQuery))); return actionBuilder; } @@ -1587,7 +1587,7 @@ public static BotActionBuilder OnPreCheckoutQuery(this BotActionCatalogFactory f { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.PreCheckoutQuery))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.PreCheckoutQuery))); return actionBuilder; } @@ -1610,7 +1610,7 @@ public static BotActionBuilder OnPollUpdate(this BotActionCatalogFactory factory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Poll))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Poll))); return actionBuilder; } @@ -1633,7 +1633,7 @@ public static BotActionBuilder OnPollAnswer(this BotActionCatalogFactory factory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.PollAnswer))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.PollAnswer))); return actionBuilder; } @@ -1657,7 +1657,7 @@ public static BotActionBuilder OnMyChatMember(this BotActionCatalogFactory facto { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MyChatMember))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MyChatMember))); return actionBuilder; } @@ -1680,7 +1680,7 @@ public static BotActionBuilder OnChatMember(this BotActionCatalogFactory factory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatMember))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatMember))); return actionBuilder; } @@ -1704,7 +1704,7 @@ public static BotActionBuilder OnChatJoinRequest(this BotActionCatalogFactory fa { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatJoinRequest))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatJoinRequest))); return actionBuilder; } @@ -1728,7 +1728,7 @@ public static BotActionBuilder OnMessageReaction(this BotActionCatalogFactory fa { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MessageReaction))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MessageReaction))); return actionBuilder; } @@ -1752,7 +1752,7 @@ public static BotActionBuilder OnMessageReactionCount(this BotActionCatalogFacto { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MessageReactionCount))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.MessageReactionCount))); return actionBuilder; } @@ -1775,7 +1775,7 @@ public static BotActionBuilder OnChatBoost(this BotActionCatalogFactory factory, { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatBoost))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.ChatBoost))); return actionBuilder; } @@ -1799,7 +1799,7 @@ public static BotActionBuilder OnRemovedChatBoost(this BotActionCatalogFactory f { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.RemovedChatBoost))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.RemovedChatBoost))); return actionBuilder; } @@ -1823,7 +1823,7 @@ public static BotActionBuilder OnBusinessConnection(this BotActionCatalogFactory { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.BusinessConnection))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.BusinessConnection))); return actionBuilder; } @@ -1847,7 +1847,7 @@ public static BotActionBuilder OnBusinessMessage(this BotActionCatalogFactory fa { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.BusinessMessage))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.BusinessMessage))); return actionBuilder; } @@ -1871,7 +1871,7 @@ public static BotActionBuilder OnEditedBusinessMessage(this BotActionCatalogFact { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedBusinessMessage))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.EditedBusinessMessage))); return actionBuilder; } @@ -1895,7 +1895,7 @@ public static BotActionBuilder OnDeletedBusinessMessages(this BotActionCatalogFa { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.DeletedBusinessMessages))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.DeletedBusinessMessages))); return actionBuilder; } @@ -1919,7 +1919,7 @@ public static BotActionBuilder OnUnknownUpdate(this BotActionCatalogFactory fact { var actionBuilder = factory.OnUpdate(condition, handler); - actionBuilder.SetType(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Unknown))); + actionBuilder.SetCategory(new UpdateCategory(nameof(UpdateType), nameof(UpdateType.Unknown))); return actionBuilder; } diff --git a/src/Navigator/Strategy/INavigatorStrategy.cs b/src/Navigator/Strategy/INavigatorStrategy.cs index 33e4ab6..a5c01f7 100644 --- a/src/Navigator/Strategy/INavigatorStrategy.cs +++ b/src/Navigator/Strategy/INavigatorStrategy.cs @@ -2,7 +2,15 @@ namespace Navigator.Strategy; +/// +/// Interface for a strategy implementation for dynamic decision-making based on incoming updates. +/// public interface INavigatorStrategy { + /// + /// Invokes the strategy for the given . + /// + /// The update that triggered the strategy. + /// public Task Invoke(Update update); } \ No newline at end of file diff --git a/src/Navigator/Strategy/TypeProvider/IArgumentTypeProvider.cs b/src/Navigator/Strategy/TypeProvider/IArgumentTypeProvider.cs index 0b242bd..ccb1cd9 100644 --- a/src/Navigator/Strategy/TypeProvider/IArgumentTypeProvider.cs +++ b/src/Navigator/Strategy/TypeProvider/IArgumentTypeProvider.cs @@ -3,9 +3,22 @@ namespace Navigator.Strategy.TypeProvider; +/// +/// Provides an argument of a given type for a given and . +/// public interface IArgumentTypeProvider { + /// + /// Gets priority of the provider. + /// public ushort Priority { get; } + /// + /// Gets an instance of the argument requested given the supplied and . + /// + /// The type of the argument to get. + /// The supplied . + /// The supplied . + /// An instance of the argument requested. public ValueTask GetArgument(Type type, Update update, BotAction action); } \ No newline at end of file From a9a68746b58ebf7127ae59990dcfb185a9858eeb Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 16:54:07 +0200 Subject: [PATCH 65/66] chore: clean sample --- src/Sample/Program.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Sample/Program.cs b/src/Sample/Program.cs index 4262871..f779de1 100644 --- a/src/Sample/Program.cs +++ b/src/Sample/Program.cs @@ -47,13 +47,6 @@ }) .WithCooldown(TimeSpan.FromSeconds(30)); -// This action will be triggered if the user sends a message in the style of `/sad`. -bot.OnCommand("sad", - async (INavigatorClient client, Chat chat) => - { - await client.SendStickerAsync(chat, "CAACAgQAAxkBAAI5DF59uqkJYnqzc5LcnEC_bdp0rerIAAJsAwACmOejAAG_qYNUT_L_exgE"); - }); - app.MapNavigator(); app.Run(); \ No newline at end of file From 50f697b2f43470c6c62c1ee314436cad583f6579 Mon Sep 17 00:00:00 2001 From: Lucas Maximiliano Marino Date: Wed, 21 Aug 2024 16:58:20 +0200 Subject: [PATCH 66/66] feat: update the LICENSE --- LICENSE | 149 ++++++++++++++++++--------------- README.md | 12 +-- src/Navigator.sln | 1 + src/Navigator/Navigator.csproj | 2 +- 4 files changed, 86 insertions(+), 78 deletions(-) diff --git a/LICENSE b/LICENSE index 0ad25db..f288702 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ - GNU AFFERO GENERAL PUBLIC LICENSE - Version 3, 19 November 2007 + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies @@ -7,15 +7,17 @@ Preamble - The GNU Affero General Public License is a free, copyleft license for -software and other kinds of works, specifically designed to ensure -cooperation with the community in the case of network server software. + The GNU General Public License is a free, copyleft license for +software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, -our General Public Licenses are intended to guarantee your freedom to +the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free -software for all its users. +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you @@ -24,34 +26,44 @@ them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. - Developers that use our General Public Licenses protect your rights -with two steps: (1) assert copyright on the software, and (2) offer -you this License which gives you legal permission to copy, distribute -and/or modify the software. - - A secondary benefit of defending all users' freedom is that -improvements made in alternate versions of the program, if they -receive widespread use, become available for other developers to -incorporate. Many developers of free software are heartened and -encouraged by the resulting cooperation. However, in the case of -software used on network servers, this result may fail to come about. -The GNU General Public License permits making a modified version and -letting the public access it on a server without ever releasing its -source code to the public. - - The GNU Affero General Public License is designed specifically to -ensure that, in such cases, the modified source code becomes available -to the community. It requires the operator of a network server to -provide the source code of the modified version running there to the -users of that server. Therefore, public use of a modified version, on -a publicly accessible server, gives the public access to the source -code of the modified version. - - An older license, called the Affero General Public License and -published by Affero, was designed to accomplish similar goals. This is -a different license, not a version of the Affero GPL, but Affero has -released a new version of the Affero GPL which permits relicensing under -this license. + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. @@ -60,7 +72,7 @@ modification follow. 0. Definitions. - "This License" refers to version 3 of the GNU Affero General Public License. + "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. @@ -537,45 +549,35 @@ to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. - 13. Remote Network Interaction; Use with the GNU General Public License. - - Notwithstanding any other provision of this License, if you modify the -Program, your modified version must prominently offer all users -interacting with it remotely through a computer network (if your version -supports such interaction) an opportunity to receive the Corresponding -Source of your version by providing access to the Corresponding Source -from a network server at no charge, through some standard or customary -means of facilitating copying of software. This Corresponding Source -shall include the Corresponding Source for any work covered by version 3 -of the GNU General Public License that is incorporated pursuant to the -following paragraph. + 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed -under version 3 of the GNU General Public License into a single +under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, -but the work with which it is combined will remain governed by version -3 of the GNU General Public License. +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of -the GNU Affero General Public License from time to time. Such new versions -will be similar in spirit to the present version, but may differ in detail to +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU Affero General +Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the -GNU Affero General Public License, you may choose any version ever published +GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future -versions of the GNU Affero General Public License can be used, that proxy's +versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. @@ -633,29 +635,40 @@ the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. + GNU General Public License for more details. - You should have received a copy of the GNU Affero General Public License + You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. - If your software can interact with users remotely through a computer -network, you should also make sure that it provides a way for users to -get its source. For example, if your program is a web application, its -interface could display a "Source" link that leads users to an archive -of the code. There are many ways you could offer source, and different -solutions will be better for different programs; see section 13 for the -specific requirements. + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU AGPL, see +For more information on this, and how to apply and follow the GNU GPL, see . + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md index 9ea3a5d..a833477 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A highly opinionated telegram bot framework, mainly based on [Telegram.Bot](https://github.com/TelegramBots/Telegram.Bot). -The only requirement is `Microsoft.AspNetCore.App (>= 8.0)`. +The only requirement is `Microsoft.AspNetCore.App (>= 8.0)`. The usage is very simple yet powerful: @@ -39,12 +39,6 @@ app.MapNavigator(); app.Run(); ``` -## Packages - -| Package | Last Stable | Last Prerelease | -|-----------|-------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------| -| Navigator | [![package.nav](https://img.shields.io/nuget/v/Navigator?style=flat-square)](https://www.nuget.org/packages/Navigator/) | [![package.nav.pre](https://img.shields.io/nuget/vpre/Navigator?style=flat-square)](https://www.nuget.org/packages/Navigator/) | - # Examples Some examples can be found in the [samples](https://github.com/navigatorframework/navigator/src/) repository. @@ -60,7 +54,7 @@ Navigator Framework Copyright (C) 2019-2024 Lucas Maximiliano Marino This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published +it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. @@ -69,5 +63,5 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. -You should have received a copy of the GNU Affero General Public License +You should have received a copy of the GNU General Public License along with this program. If not, see . \ No newline at end of file diff --git a/src/Navigator.sln b/src/Navigator.sln index 49d3e9b..9bbbd7b 100644 --- a/src/Navigator.sln +++ b/src/Navigator.sln @@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".solution-items", ".solutio ..\.github\workflows\package.navigator.yml = ..\.github\workflows\package.navigator.yml global.json = global.json nuget.config = nuget.config + ..\LICENSE = ..\LICENSE EndProjectSection EndProject Global diff --git a/src/Navigator/Navigator.csproj b/src/Navigator/Navigator.csproj index 905d10b..ace5dc9 100644 --- a/src/Navigator/Navigator.csproj +++ b/src/Navigator/Navigator.csproj @@ -14,7 +14,7 @@ README.md Telegram, Bot, Framework, Navigator true - AGPL-3.0-only + GPL-3.0-only Copyright © Lucas Maximiliano Marino 2023