From d99b10f6920842acc51d3bc8f301884e32538023 Mon Sep 17 00:00:00 2001 From: Rikitav Date: Sun, 24 Aug 2025 01:13:35 +0400 Subject: [PATCH] * Added new method for filters report inspection * Added ArgumentCount filter * Fixed AddHandler method throwing exception on handler without parameterless constructors --- .../Annotations/CommandArgumentAttributes.cs | 8 ++- Telegrator/Filters/CommandArgumentFilter.cs | 12 ++++ .../Components/FiltersFallbackReport.cs | 56 +++++++++++----- Telegrator/Providers/HandlersCollection.cs | 1 - Telegrator/TypesExtensions.cs | 65 +++++++++++++------ 5 files changed, 103 insertions(+), 39 deletions(-) diff --git a/Telegrator/Annotations/CommandArgumentAttributes.cs b/Telegrator/Annotations/CommandArgumentAttributes.cs index ceac359..cff75c0 100644 --- a/Telegrator/Annotations/CommandArgumentAttributes.cs +++ b/Telegrator/Annotations/CommandArgumentAttributes.cs @@ -3,6 +3,10 @@ using Telegrator.Filters; namespace Telegrator.Annotations { + public class ArgumentCountAttribute(int count) + : MessageFilterAttribute(new ArgumentCountFilter(count)) + { } + /// /// Attribute for filtering messages where a command argument starts with the specified content. /// @@ -50,7 +54,7 @@ namespace Telegrator.Annotations /// The regex options to use for the pattern matching. /// The timeout for the regex match operation. /// The index of the argument to check (0-based). - public class ArgumentRegexAttribute(string pattern, RegexOptions options = RegexOptions.None, TimeSpan matchTimeout = default, int index = 0) - : MessageFilterAttribute(new ArgumentRegexFilter(pattern, options, matchTimeout, index)) + public class ArgumentRegexAttribute(string pattern, RegexOptions options = RegexOptions.None, int index = 0) + : MessageFilterAttribute(new ArgumentRegexFilter(pattern, options, index: index)) { } } diff --git a/Telegrator/Filters/CommandArgumentFilter.cs b/Telegrator/Filters/CommandArgumentFilter.cs index 13ef094..c41b4f8 100644 --- a/Telegrator/Filters/CommandArgumentFilter.cs +++ b/Telegrator/Filters/CommandArgumentFilter.cs @@ -42,6 +42,18 @@ namespace Telegrator.Filters protected abstract bool CanPassNext(FilterExecutionContext context); } + public class ArgumentCountFilter(int count) : Filter + { + private readonly int Count = count; + + public override bool CanPass(FilterExecutionContext context) + { + CommandHandlerAttribute attr = context.CompletedFilters.Get(0); + string[] args = attr.Arguments ??= context.Input.SplitArgs(); + return args.Length >= Count; + } + } + /// /// Filter that checks if a command argument starts with a specified content. /// diff --git a/Telegrator/Handlers/Components/FiltersFallbackReport.cs b/Telegrator/Handlers/Components/FiltersFallbackReport.cs index b1fb1db..fb1b9f7 100644 --- a/Telegrator/Handlers/Components/FiltersFallbackReport.cs +++ b/Telegrator/Handlers/Components/FiltersFallbackReport.cs @@ -38,27 +38,53 @@ namespace Telegrator.Handlers.Components /// public List UpdateFilters { get; } = []; + public bool Only(string name, int index = 0) + { + FilterFallbackInfo? info = UpdateFilters.SingleSafe(info => info.Failed); + if (info != null && info.Name != name) + return false; + + FilterFallbackInfo? target = UpdateFilters.ElementAtOrDefault(index); + return ReferenceEquals(target, info); + } + + public bool Only(string[] names) + { + return UpdateFilters + .Where(info => info.Failed) + .Select(info => info.Name) + .SequenceEqual(names); + } + + public bool Except(string name, int index = 0) + { + FilterFallbackInfo? info = UpdateFilters.SingleSafe(info => !info.Failed); + if (info != null && info.Name != name) + return false; + + FilterFallbackInfo? target = UpdateFilters.ElementAtOrDefault(index); + return ReferenceEquals(target, info); + } + + public bool Except(string[] names) + { + return UpdateFilters + .Where(info => !info.Failed) + .Select(info => info.Name) + .SequenceEqual(names); + } + + public bool ExceptAttribute(int index = 0) where T : UpdateFilterAttributeBase + => Except(nameof(T), index); + /// /// Checks if the failure is due to a specific attribute type, excluding other failures. /// /// The attribute type to check for. /// The index of the filter to check (default: 0). /// True if the failure is exclusively due to the specified attribute type; otherwise, false. - public bool ExceptAttribute(int index = 0) where T : UpdateFilterAttributeBase - { - string name = typeof(T).Name; - - IEnumerable failed = UpdateFilters.Where(info => info.Failed); - if (failed.Count() != 1) - return false; - - FilterFallbackInfo info = failed.ElementAt(0); - if (info.Name != name) - return false; - - FilterFallbackInfo? target = UpdateFilters.ElementAtOrDefault(index); - return target == info; - } + public bool OnlyAttribute(int index = 0) where T : UpdateFilterAttributeBase + => Only(nameof(T), index); } /// diff --git a/Telegrator/Providers/HandlersCollection.cs b/Telegrator/Providers/HandlersCollection.cs index d58ef53..37c4f4b 100644 --- a/Telegrator/Providers/HandlersCollection.cs +++ b/Telegrator/Providers/HandlersCollection.cs @@ -3,7 +3,6 @@ using Telegram.Bot.Types.Enums; using Telegrator.Annotations; using Telegrator.Attributes; using Telegrator.Configuration; -using Telegrator.Handlers.Components; using Telegrator.MadiatorCore; using Telegrator.MadiatorCore.Descriptors; diff --git a/Telegrator/TypesExtensions.cs b/Telegrator/TypesExtensions.cs index 3acf39c..6d2c885 100644 --- a/Telegrator/TypesExtensions.cs +++ b/Telegrator/TypesExtensions.cs @@ -1,4 +1,5 @@ -using System.Collections.ObjectModel; +using System; +using System.Collections.ObjectModel; using System.Reflection; using Telegram.Bot; using Telegram.Bot.Types; @@ -643,9 +644,6 @@ namespace Telegrator if (handlerType.IsCustomDescriptorsProvider()) { - if (!handlerType.HasParameterlessCtor()) - throw new Exception(); - ICustomDescriptorsProvider provider = (ICustomDescriptorsProvider)Activator.CreateInstance(handlerType); foreach (HandlerDescriptor handlerDescriptor in provider.DescribeHandlers()) handlers.AddDescriptor(handlerDescriptor); @@ -944,23 +942,6 @@ namespace Telegrator return source; } - /* Found built in method :_( - /// - /// Creates a new with the elements of the that were successfully cast to the - /// - /// - /// - /// - public static IEnumerable WhereCast(this IEnumerable source) - { - foreach (object value in source) - { - if (value is TResult result) - yield return result; - } - } - */ - /// /// Sets the value of a key in a dictionary, or if the key does not exist, adds it /// @@ -1027,6 +1008,32 @@ namespace Telegrator list.Add(item); } } + + public static int IndexOf(this IEnumerable source, Func predicate) + { + int index = 0; + foreach (T item in source) + { + if (predicate.Invoke(item)) + return index; + + index++; + } + + return -1; + } + + public static IEnumerable Repeat(this T item, int times) + => Enumerable.Range(0, times).Select(_ => item); + + public static T? SingleSafe(this IEnumerable source) + => source.Count() == 1 ? source.ElementAt(0) : default; + + public static T? SingleSafe(this IEnumerable source, Func predicate) + { + source = source.Where(predicate); + return source.Count() == 1 ? source.ElementAt(0) : default; + } } /// @@ -1190,6 +1197,22 @@ namespace Telegrator yield return chunk.ToString(); } } + + public static string FirstLetterToUpper(this string target) + { + char[] chars = target.ToCharArray(); + int index = chars.IndexOf(char.IsLetter); + chars[index] = char.ToUpper(chars[index]); + return new string(chars); + } + + public static string FirstLetterToLower(this string target) + { + char[] chars = target.ToCharArray(); + int index = chars.IndexOf(char.IsLetter); + chars[index] = char.ToLower(chars[index]); + return new string(chars); + } } ///