diff --git a/Telegrator.sln b/Telegrator.sln index 88c8e42..f9bed94 100644 --- a/Telegrator.sln +++ b/Telegrator.sln @@ -20,8 +20,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegrator.Analyzers", "Tel EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegrator.Hosting.Web", "Telegrator.Hosting.Web\Telegrator.Hosting.Web.csproj", "{98AB490F-6A36-CCFF-F6E6-B029D1665965}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SosalBot", "..\SosalBot\SosalBot\SosalBot.csproj", "{D6AA4D47-0DCE-520E-5779-A14EA9CB1DEC}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution AnalyzersDebug|Any CPU = AnalyzersDebug|Any CPU @@ -65,12 +63,6 @@ Global {98AB490F-6A36-CCFF-F6E6-B029D1665965}.Debug|Any CPU.Build.0 = Debug|Any CPU {98AB490F-6A36-CCFF-F6E6-B029D1665965}.Release|Any CPU.ActiveCfg = Release|Any CPU {98AB490F-6A36-CCFF-F6E6-B029D1665965}.Release|Any CPU.Build.0 = Release|Any CPU - {D6AA4D47-0DCE-520E-5779-A14EA9CB1DEC}.AnalyzersDebug|Any CPU.ActiveCfg = Release|Any CPU - {D6AA4D47-0DCE-520E-5779-A14EA9CB1DEC}.AnalyzersDebug|Any CPU.Build.0 = Release|Any CPU - {D6AA4D47-0DCE-520E-5779-A14EA9CB1DEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D6AA4D47-0DCE-520E-5779-A14EA9CB1DEC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D6AA4D47-0DCE-520E-5779-A14EA9CB1DEC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D6AA4D47-0DCE-520E-5779-A14EA9CB1DEC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Telegrator/Annotations/CommandAlliasAttribute.cs b/Telegrator/Annotations/CommandAlliasAttribute.cs index 98db005..6766028 100644 --- a/Telegrator/Annotations/CommandAlliasAttribute.cs +++ b/Telegrator/Annotations/CommandAlliasAttribute.cs @@ -47,7 +47,8 @@ namespace Telegrator.Annotations /// /// The command aliases to match against. public CommandAlliasAttribute(params string[] alliases) - : base(new CommandAlliasFilter(alliases)) => Alliases = alliases.Select(c => c.TrimStart('/')).ToArray(); + : base(new CommandAlliasFilter(alliases.Select(c => c.TrimStart('/')).ToArray())) + => Alliases = alliases.Select(c => c.TrimStart('/')).ToArray(); /// /// Gets the filtering target (Message) from the update. diff --git a/Telegrator/Annotations/CommandArgumentAttributes.cs b/Telegrator/Annotations/CommandArgumentAttributes.cs new file mode 100644 index 0000000..a38f797 --- /dev/null +++ b/Telegrator/Annotations/CommandArgumentAttributes.cs @@ -0,0 +1,25 @@ +using System.Text.RegularExpressions; +using Telegrator.Filters; + +namespace Telegrator.Annotations +{ + public class ArgumentStartsWithAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) + : MessageFilterAttribute(new ArgumentStartsWithFilter(content, comparison, index)) + { } + + public class ArgumentEndsWithAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) + : MessageFilterAttribute(new ArgumentEndsWithFilter(content, comparison, index)) + { } + + public class ArgumentContainsAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) + : MessageFilterAttribute(new ArgumentContainsFilter(content, comparison, index)) + { } + + public class ArgumentEqualsAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) + : MessageFilterAttribute(new ArgumentEqualsFilter(content, comparison, index)) + { } + + public class ArgumentRegexAttribute(string pattern, RegexOptions options = RegexOptions.None, TimeSpan matchTimeout = default, int index = 0) + : MessageFilterAttribute(new ArgumentRegexFilter(pattern, options, matchTimeout, index)) + { } +} diff --git a/Telegrator/Filters/CommandArgumentFilter.cs b/Telegrator/Filters/CommandArgumentFilter.cs index 57924a5..1274e6a 100644 --- a/Telegrator/Filters/CommandArgumentFilter.cs +++ b/Telegrator/Filters/CommandArgumentFilter.cs @@ -1,20 +1,81 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Text.RegularExpressions; using Telegram.Bot.Types; using Telegrator.Filters.Components; using Telegrator.Handlers; namespace Telegrator.Filters { - public class CommandArgumentFilter : Filter + public abstract class CommandArgumentFilterBase(int index) : Filter { + protected string Target { get; private set; } = null!; + public override bool CanPass(FilterExecutionContext context) { CommandHandlerAttribute attr = context.CompletedFilters.Get(0); string[] args = attr.Arguments ??= context.Input.SplitArgs(); + Target = args.ElementAtOrDefault(index); - return alliases.Contains(ReceivedCommand, StringComparer.InvariantCultureIgnoreCase); + if (Target == null) + return false; + + return CanPassNext(context); + } + + protected abstract bool CanPassNext(FilterExecutionContext context); + } + + public class ArgumentStartsWithFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) : CommandArgumentFilterBase(index) + { + protected readonly string Content = content; + protected readonly StringComparison Comparison = comparison; + + protected override bool CanPassNext(FilterExecutionContext _) + => Target.StartsWith(Content, Comparison); + } + + public class ArgumentEndsWithFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) : CommandArgumentFilterBase(index) + { + protected readonly string Content = content; + protected readonly StringComparison Comparison = comparison; + + protected override bool CanPassNext(FilterExecutionContext _) + => Target.EndsWith(Content, Comparison); + } + + public class ArgumentContainsFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) : CommandArgumentFilterBase(index) + { + protected readonly string Content = content; + protected readonly StringComparison Comparison = comparison; + + protected override bool CanPassNext(FilterExecutionContext _) + => Target.IndexOf(Content, Comparison) >= 0; + } + + public class ArgumentEqualsFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) : CommandArgumentFilterBase(index) + { + protected readonly string Content = content; + protected readonly StringComparison Comparison = comparison; + + protected override bool CanPassNext(FilterExecutionContext _) + => Target.Equals(Content, Comparison); + } + + public class ArgumentRegexFilter : CommandArgumentFilterBase + { + private readonly Regex _regex; + + public Match Match { get; private set; } = null!; + + public ArgumentRegexFilter(Regex regex, int index = 0) + : base(index) => _regex = regex; + + public ArgumentRegexFilter(string pattern, RegexOptions options = RegexOptions.None, TimeSpan matchTimeout = default, int index = 0) + : base(index) => _regex = new Regex(pattern, options, matchTimeout); + + protected override bool CanPassNext(FilterExecutionContext context) + { + Match = _regex.Match(Target); + return Match.Success; } } } diff --git a/Telegrator/Handlers/Components/BranchingUpdateHandler.cs b/Telegrator/Handlers/Components/BranchingUpdateHandler.cs index 279488f..338627c 100644 --- a/Telegrator/Handlers/Components/BranchingUpdateHandler.cs +++ b/Telegrator/Handlers/Components/BranchingUpdateHandler.cs @@ -29,7 +29,7 @@ namespace Telegrator.Handlers.Components /// /// Gets the allowed return types for branch methods. /// - protected virtual Type[] AllowedBranchReturnTypes => [typeof(void), typeof(Task)]; + protected virtual Type[] AllowedBranchReturnTypes => [typeof(void), typeof(Task)]; /// /// Gets the cancellation token for the current execution. @@ -75,10 +75,10 @@ namespace Telegrator.Handlers.Components Type thisType = GetType(); if (branch.GetParameters().Length != 0) - throw new Exception(); + throw new Exception("Branch method must have no parameters."); if (!AllowedBranchReturnTypes.Any(branch.ReturnType.Equals)) - throw new Exception(); + throw new Exception("Branch method must have one of allowed return types. [void, Task]"); try { diff --git a/Telegrator/MadiatorCore/Descriptors/DescriptorFiltersSet.cs b/Telegrator/MadiatorCore/Descriptors/DescriptorFiltersSet.cs index f6e20e6..ec2aacc 100644 --- a/Telegrator/MadiatorCore/Descriptors/DescriptorFiltersSet.cs +++ b/Telegrator/MadiatorCore/Descriptors/DescriptorFiltersSet.cs @@ -1,5 +1,4 @@ using Telegram.Bot.Types; -using Telegrator.Filters; using Telegrator.Filters.Components; using Telegrator.Handlers.Components; using Telegrator.Logging; diff --git a/Telegrator/Result.cs b/Telegrator/Result.cs index ac745fb..98d9be1 100644 --- a/Telegrator/Result.cs +++ b/Telegrator/Result.cs @@ -38,6 +38,7 @@ namespace Telegrator /// /// Inside - let handler's main block be executed /// Inside - tells that he can stop describing, as needed handler was found + /// Inside - let continue describing /// /// /// @@ -58,7 +59,7 @@ namespace Telegrator /// /// Represents 'continue'. Use cases: /// - /// Inside - let router continue describing + /// Inside - let continue describing /// Inside - Tells to continue describing handlers /// ///