From 78c7f41489654f503f097653a9a2d597d2be2ec8 Mon Sep 17 00:00:00 2001 From: Rikitav Date: Fri, 25 Jul 2025 01:26:32 +0400 Subject: [PATCH] Removed doubled filters variations for reply-chain message filtering Instead using MessageRepliedAttribute to filter messages in reply-chain Old types renamed to new framework name --- README.md | 9 +- .../Components/ITelegramBotHost.cs | 2 +- Telegrator.Hosting/GlobalSuppressions.cs | 1 + Telegrator.Hosting/TelegramBotHost.cs | 2 +- Telegrator.Hosting/Telegrator.Hosting.csproj | 1 - .../Annotations/MessageRepliedAttributes.cs | 18 + .../Annotations/RepliedMentionedAttribute.cs | 44 -- .../RepliedMessageChatFilterAttributes.cs | 102 ----- .../RepliedMessageFilterAttributes.cs | 114 ------ .../RepliedMessageSenderFilterAttributes.cs | 94 ----- .../RepliedMessageTextFilterAttributes.cs | 52 --- .../Annotations/RepliedToMeAttribute.cs | 11 - Telegrator/Filters/MentionedFilter.cs | 8 +- Telegrator/Filters/MessageChatFilters.cs | 10 +- Telegrator/Filters/MessageFilters.cs | 73 ++-- Telegrator/Filters/MessageRepliedFilters.cs | 62 +++ Telegrator/Filters/MessageSenderFilters.cs | 15 +- Telegrator/Filters/MessageTextFilters.cs | 13 +- Telegrator/Filters/RepliedMentionedFilter.cs | 56 --- .../Filters/RepliedMessageChatFilters.cs | 211 ---------- Telegrator/Filters/RepliedMessageFilters.cs | 383 ------------------ .../Filters/RepliedMessageSenderFilters.cs | 192 --------- .../Filters/RepliedMessageTextFilters.cs | 123 ------ Telegrator/Filters/RepliedToMeFilter.cs | 16 - ...activeTelegramBot.cs => ITelegratorBot.cs} | 2 +- Telegrator/TelegratorClient.cs | 2 +- 26 files changed, 158 insertions(+), 1458 deletions(-) create mode 100644 Telegrator/Annotations/MessageRepliedAttributes.cs delete mode 100644 Telegrator/Annotations/RepliedMentionedAttribute.cs delete mode 100644 Telegrator/Annotations/RepliedMessageChatFilterAttributes.cs delete mode 100644 Telegrator/Annotations/RepliedMessageFilterAttributes.cs delete mode 100644 Telegrator/Annotations/RepliedMessageSenderFilterAttributes.cs delete mode 100644 Telegrator/Annotations/RepliedMessageTextFilterAttributes.cs delete mode 100644 Telegrator/Annotations/RepliedToMeAttribute.cs create mode 100644 Telegrator/Filters/MessageRepliedFilters.cs delete mode 100644 Telegrator/Filters/RepliedMentionedFilter.cs delete mode 100644 Telegrator/Filters/RepliedMessageChatFilters.cs delete mode 100644 Telegrator/Filters/RepliedMessageFilters.cs delete mode 100644 Telegrator/Filters/RepliedMessageSenderFilters.cs delete mode 100644 Telegrator/Filters/RepliedMessageTextFilters.cs delete mode 100644 Telegrator/Filters/RepliedToMeFilter.cs rename Telegrator/{IReactiveTelegramBot.cs => ITelegratorBot.cs} (90%) diff --git a/README.md b/README.md index 2a14da3..8597615 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,11 @@ Telegrator is a next-generation framework for building Telegram bots in C#, insp ### 1. Installation ```shell -# Coming soon: will be available via NuGet -# dotnet add package Telegrator +# .NET CLI +dotnet add package Telegrator + +# NuGet CLI +NuGet\Install-Package Telegrator ``` ### 2. Minimal Bot Example @@ -59,7 +62,7 @@ public class HelloHandler : MessageHandler } // Registration and launch: -var bot = new ReactiveClient(""); +var bot = new TelegratorClient(""); bot.Handlers.AddHandler(); bot.StartReceiving(); ``` diff --git a/Telegrator.Hosting/Components/ITelegramBotHost.cs b/Telegrator.Hosting/Components/ITelegramBotHost.cs index 956dc58..7f0d6a3 100644 --- a/Telegrator.Hosting/Components/ITelegramBotHost.cs +++ b/Telegrator.Hosting/Components/ITelegramBotHost.cs @@ -7,7 +7,7 @@ namespace Telegrator.Hosting.Components /// Interface for Telegram bot hosts. /// Combines host application capabilities with reactive Telegram bot functionality. /// - public interface ITelegramBotHost : IHost, IReactiveTelegramBot + public interface ITelegramBotHost : IHost, ITelegratorBot { } diff --git a/Telegrator.Hosting/GlobalSuppressions.cs b/Telegrator.Hosting/GlobalSuppressions.cs index 7f9eb35..cba9507 100644 --- a/Telegrator.Hosting/GlobalSuppressions.cs +++ b/Telegrator.Hosting/GlobalSuppressions.cs @@ -6,3 +6,4 @@ using System.Diagnostics.CodeAnalysis; [assembly: SuppressMessage("Style", "IDE0290")] +[assembly: SuppressMessage("Style", "IDE0090")] diff --git a/Telegrator.Hosting/TelegramBotHost.cs b/Telegrator.Hosting/TelegramBotHost.cs index ea6164d..aadc395 100644 --- a/Telegrator.Hosting/TelegramBotHost.cs +++ b/Telegrator.Hosting/TelegramBotHost.cs @@ -111,7 +111,7 @@ namespace Telegrator.Hosting //hostApplicationBuilder.Services.AddSingleton(this); hostApplicationBuilder.Services.AddSingleton(this); - hostApplicationBuilder.Services.AddSingleton(this); + hostApplicationBuilder.Services.AddSingleton(this); hostApplicationBuilder.Services.AddSingleton(handlers); } } diff --git a/Telegrator.Hosting/Telegrator.Hosting.csproj b/Telegrator.Hosting/Telegrator.Hosting.csproj index ad9f9e6..5ce8471 100644 --- a/Telegrator.Hosting/Telegrator.Hosting.csproj +++ b/Telegrator.Hosting/Telegrator.Hosting.csproj @@ -10,7 +10,6 @@ Telegrator : Telegram.Bot mediator framework telegrator_nuget.png - README.md https://github.com/Rikitav/Telegrator telegram;bot;mediator;attributes;aspect;hosting;host;framework;easy;simple;handlers True diff --git a/Telegrator/Annotations/MessageRepliedAttributes.cs b/Telegrator/Annotations/MessageRepliedAttributes.cs new file mode 100644 index 0000000..cfd5ba4 --- /dev/null +++ b/Telegrator/Annotations/MessageRepliedAttributes.cs @@ -0,0 +1,18 @@ +using Telegrator.Filters; + +namespace Telegrator.Annotations +{ + /// + /// Attribute for filtering messages with reply to messages of this bot. + /// + public class MeRepliedAttribute() + : MessageFilterAttribute(new MeRepliedFilter()) + { } + + /// + /// Attribute for filtering messages in reply chain. + /// + public class MessageRepliedAttribute(int replyDepth = 1) + : MessageFilterAttribute(new MessageRepliedFilter(replyDepth)) + { } +} diff --git a/Telegrator/Annotations/RepliedMentionedAttribute.cs b/Telegrator/Annotations/RepliedMentionedAttribute.cs deleted file mode 100644 index 1dfdba3..0000000 --- a/Telegrator/Annotations/RepliedMentionedAttribute.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Telegram.Bot.Types.Enums; -using Telegrator.Filters; - -namespace Telegrator.Annotations -{ - /// - /// Attribute for filtering messages that are replies to messages containing mentions. - /// Allows handlers to respond to messages that reply to messages with specific mentions. - /// - public class RepliedMentionedAttribute : MessageFilterAttribute - { - /// - /// Initializes a new instance of the RepliedMentionedAttribute that matches replies to any mention. - /// - /// The depth of the reply chain to check (default: 1). - public RepliedMentionedAttribute(int replyDepth = 1) - : base(new RepliedMessageHasEntityFilter(MessageEntityType.Mention, 0, null, replyDepth), new RepliedMentionedFilter(replyDepth)) { } - - /// - /// Initializes a new instance of the RepliedMentionedAttribute that matches replies to mentions at a specific offset. - /// - /// The offset position where the mention should occur in the replied message. - /// The depth of the reply chain to check (default: 1). - public RepliedMentionedAttribute(int offset, int replyDepth = 1) - : base(new RepliedMessageHasEntityFilter(MessageEntityType.Mention, offset, null, replyDepth), new RepliedMentionedFilter(replyDepth)) { } - - /// - /// Initializes a new instance of the RepliedMentionedAttribute that matches replies to a specific mention. - /// - /// The specific mention text to match in the replied message. - /// The depth of the reply chain to check (default: 1). - public RepliedMentionedAttribute(string mention, int replyDepth = 1) - : base(new RepliedMessageHasEntityFilter(MessageEntityType.Mention, replyDepth), new RepliedMentionedFilter(mention, replyDepth)) { } - - /// - /// Initializes a new instance of the RepliedMentionedAttribute that matches replies to a specific mention at a specific offset. - /// - /// The specific mention text to match in the replied message. - /// The offset position where the mention should occur in the replied message. - /// The depth of the reply chain to check (default: 1). - public RepliedMentionedAttribute(string mention, int offset, int replyDepth = 1) - : base(new RepliedMessageHasEntityFilter(MessageEntityType.Mention, offset, null, replyDepth), new RepliedMentionedFilter(mention, replyDepth)) { } - } -} diff --git a/Telegrator/Annotations/RepliedMessageChatFilterAttributes.cs b/Telegrator/Annotations/RepliedMessageChatFilterAttributes.cs deleted file mode 100644 index 98168e6..0000000 --- a/Telegrator/Annotations/RepliedMessageChatFilterAttributes.cs +++ /dev/null @@ -1,102 +0,0 @@ -using Telegram.Bot.Types.Enums; -using Telegrator.Filters; - -namespace Telegrator.Annotations -{ - /// - /// Attribute for filtering messages where the replied-to message was sent in a forum chat. - /// - /// How many levels up the reply chain to check (default: 1) - public class RepliedChatIsForumAttribute(int replyDepth = 1) - : MessageFilterAttribute(new RepliedMessageChatIsForumFilter(replyDepth)) - { } - - /// - /// Attribute for filtering messages where the replied-to message was sent in a specific chat by ID. - /// - /// The chat ID to match - /// How many levels up the reply chain to check (default: 1) - public class RepliedChatIdAttribute(long id, int replyDepth = 1) - : MessageFilterAttribute(new RepliedMessageChatIdFilter(id, replyDepth)) - { } - - /// - /// Attribute for filtering messages where the replied-to message was sent in a chat of a specific type. - /// - /// The chat type to match - /// How many levels up the reply chain to check (default: 1) - public class RepliedChatTypeAttribute(ChatType type, int replyDepth = 1) - : MessageFilterAttribute(new RepliedMessageChatTypeFilter(type, replyDepth)) - { } - - /// - /// Attribute for filtering messages based on the chat title of the replied-to message. - /// - public class RepliedChatTitleAttribute : MessageFilterAttribute - { - /// - /// Initializes the attribute to filter messages where the replied-to message is from a chat with a specific title and comparison method. - /// - /// The chat title to match - /// The string comparison method - /// How many levels up the reply chain to check (default: 1) - public RepliedChatTitleAttribute(string? title, StringComparison comparison, int replyDepth = 1) - : base(new RepliedMessageChatTitleFilter(title, comparison, replyDepth)) { } - - /// - /// Initializes the attribute to filter messages where the replied-to message is from a chat with a specific title. - /// - /// The chat title to match - /// How many levels up the reply chain to check (default: 1) - public RepliedChatTitleAttribute(string? title, int replyDepth = 1) - : base(new RepliedMessageChatTitleFilter(title, StringComparison.InvariantCulture, replyDepth)) { } - } - - /// - /// Attribute for filtering messages based on the chat username of the replied-to message. - /// - public class RepliedChatUsernameAttribute : MessageFilterAttribute - { - /// - /// Initializes the attribute to filter messages where the replied-to message is from a chat with a specific username and comparison method. - /// - /// The chat username to match - /// The string comparison method - /// How many levels up the reply chain to check (default: 1) - public RepliedChatUsernameAttribute(string? userName, StringComparison comparison, int replyDepth = 1) - : base(new RepliedMessageChatUsernameFilter(userName, comparison, replyDepth)) { } - - /// - /// Initializes the attribute to filter messages where the replied-to message is from a chat with a specific username. - /// - /// The chat username to match - /// How many levels up the reply chain to check (default: 1) - public RepliedChatUsernameAttribute(string? userName, int replyDepth = 1) - : base(new RepliedMessageChatUsernameFilter(userName, replyDepth)) { } - } - - /// - /// Attribute for filtering messages based on the chat name of the replied-to message. - /// - public class RepliedChatNameAttribute : MessageFilterAttribute - { - /// - /// Initializes the attribute to filter messages where the replied-to message is from a chat with specific first and last names. - /// - /// The first name to match - /// The last name to match (optional) - /// The string comparison method - /// How many levels up the reply chain to check (default: 1) - public RepliedChatNameAttribute(string? firstName, string? lastName, StringComparison comparison, int replyDepth = 1) - : base(new RepliedMessageChatNameFilter(firstName, lastName, comparison, replyDepth)) { } - - /// - /// Initializes the attribute to filter messages where the replied-to message is from a chat with specific first and last names. - /// - /// The first name to match - /// The last name to match (optional) - /// How many levels up the reply chain to check (default: 1) - public RepliedChatNameAttribute(string? firstName, string? lastName, int replyDepth = 1) - : base(new RepliedMessageChatNameFilter(firstName, lastName, StringComparison.InvariantCulture, replyDepth)) { } - } -} diff --git a/Telegrator/Annotations/RepliedMessageFilterAttributes.cs b/Telegrator/Annotations/RepliedMessageFilterAttributes.cs deleted file mode 100644 index 284d3a7..0000000 --- a/Telegrator/Annotations/RepliedMessageFilterAttributes.cs +++ /dev/null @@ -1,114 +0,0 @@ -using Telegram.Bot.Types.Enums; -using Telegrator.Filters; - -namespace Telegrator.Annotations -{ - /// - /// Attribute for filtering messages that are replies to other messages. - /// - /// How many levels up the reply chain to check (default: 1) - public class MessageRepliedAttribute(int replyDepth = 1) - : MessageFilterAttribute(new MessageRepliedFilter(replyDepth)) - { } - - /// - /// Attribute for filtering messages where the replied-to message contains dice throws with specific values. - /// - public class RepliedDiceThrowedAttribute : MessageFilterAttribute - { - /// - /// Initializes the attribute to filter messages where the replied-to message contains a dice throw with a specific value. - /// - /// The dice value to match - /// How many levels up the reply chain to check (default: 1) - public RepliedDiceThrowedAttribute(int value, int replyDepth = 1) - : base(new RepliedDiceThrowedFilter(value, replyDepth)) { } - - /// - /// Initializes the attribute to filter messages where the replied-to message contains a dice throw with a specific type and value. - /// - /// The type of dice - /// The dice value to match - /// How many levels up the reply chain to check (default: 1) - public RepliedDiceThrowedAttribute(DiceType diceType, int value, int replyDepth = 1) - : base(new RepliedDiceThrowedFilter(diceType, value, replyDepth)) { } - } - - /// - /// Attribute for filtering messages where the replied-to message was automatically forwarded. - /// - /// How many levels up the reply chain to check (default: 1) - public class RepliedIsAutomaticFormwardMessageAttribute(int replyDepth = 1) - : MessageFilterAttribute(new RepliedIsAutomaticFormwardMessageFilter(replyDepth)) - { } - - /// - /// Attribute for filtering messages where the replied-to message was sent while the user was offline. - /// - /// How many levels up the reply chain to check (default: 1) - public class RepliedIsFromOfflineMessageAttribute(int replyDepth = 1) - : MessageFilterAttribute(new RepliedIsFromOfflineMessageFilter(replyDepth)) - { } - - /// - /// Attribute for filtering messages where the replied-to message is a service message. - /// - /// How many levels up the reply chain to check (default: 1) - public class RepliedIsServiceMessageMessageAttribute(int replyDepth = 1) - : MessageFilterAttribute(new RepliedIsServiceMessageMessageFilter(replyDepth)) - { } - - /// - /// Attribute for filtering messages where the replied-to message is a topic message in forum chats. - /// - /// How many levels up the reply chain to check (default: 1) - public class RepliedIsTopicMessageMessageAttribut(int replyDepth = 1) - : MessageFilterAttribute(new RepliedIsServiceMessageMessageFilter(replyDepth)) - { } - - /// - /// Attribute for filtering messages based on entities in the replied-to message. - /// - public class RepliedMessageHasEntityAttribute : MessageFilterAttribute - { - /// - /// Initializes the attribute to filter messages where the replied-to message has a specific entity type. - /// - /// The entity type to match - /// How many levels up the reply chain to check (default: 1) - public RepliedMessageHasEntityAttribute(MessageEntityType type, int replyDepth = 1) - : base(new RepliedMessageHasEntityFilter(type, replyDepth)) { } - - /// - /// Initializes the attribute to filter messages where the replied-to message has a specific entity type at a specific position. - /// - /// The entity type to match - /// The starting position of the entity - /// The length of the entity (optional) - /// How many levels up the reply chain to check (default: 1) - public RepliedMessageHasEntityAttribute(MessageEntityType type, int offset, int? length, int replyDepth = 1) - : base(new RepliedMessageHasEntityFilter(type, offset, length, replyDepth)) { } - - /// - /// Initializes the attribute to filter messages where the replied-to message has a specific entity type with specific content. - /// - /// The entity type to match - /// The content that the entity should contain - /// The string comparison method - /// How many levels up the reply chain to check (default: 1) - public RepliedMessageHasEntityAttribute(MessageEntityType type, string content, StringComparison stringComparison = StringComparison.CurrentCulture, int replyDepth = 1) - : base(new RepliedMessageHasEntityFilter(type, content, stringComparison, replyDepth)) { } - - /// - /// Initializes the attribute to filter messages where the replied-to message has a specific entity type at a specific position with specific content. - /// - /// The entity type to match - /// The starting position of the entity - /// The length of the entity (optional) - /// The content that the entity should contain - /// The string comparison method - /// How many levels up the reply chain to check (default: 1) - public RepliedMessageHasEntityAttribute(MessageEntityType type, int offset, int? length, string content, StringComparison stringComparison = StringComparison.CurrentCulture, int replyDepth = 1) - : base(new RepliedMessageHasEntityFilter(type, offset, length, content, stringComparison, replyDepth)) { } - } -} diff --git a/Telegrator/Annotations/RepliedMessageSenderFilterAttributes.cs b/Telegrator/Annotations/RepliedMessageSenderFilterAttributes.cs deleted file mode 100644 index ee22e48..0000000 --- a/Telegrator/Annotations/RepliedMessageSenderFilterAttributes.cs +++ /dev/null @@ -1,94 +0,0 @@ -using Telegrator.Filters; - -namespace Telegrator.Annotations -{ - /// - /// Attribute for filtering messages based on the username of the sender of the replied-to message. - /// - public class RepliedFromUsernameAttribute : MessageFilterAttribute - { - /// - /// Initializes the attribute to filter messages where the replied-to message is from a specific username. - /// - /// The username to match - /// How many levels up the reply chain to check (default: 1) - public RepliedFromUsernameAttribute(string username, int replyDepth = 1) - : base(new RepliedUsernameFilter(username, replyDepth)) { } - - /// - /// Initializes the attribute to filter messages where the replied-to message is from a specific username with custom comparison. - /// - /// The username to match - /// The string comparison method - /// How many levels up the reply chain to check (default: 1) - public RepliedFromUsernameAttribute(string username, StringComparison comparison, int replyDepth = 1) - : base(new RepliedUsernameFilter(username, comparison, replyDepth)) { } - } - - /// - /// Attribute for filtering messages based on the name of the sender of the replied-to message. - /// - public class RepliedFromUserAttribute : MessageFilterAttribute - { - /// - /// Initializes the attribute to filter messages where the replied-to message is from a user with specific names. - /// - /// The first name to match - /// The last name to match (optional) - /// The string comparison method - /// How many levels up the reply chain to check (default: 1) - public RepliedFromUserAttribute(string firstName, string? lastName, StringComparison comparison, int replyDepth = 1) - : base(new RepliedUserFilter(firstName, lastName, comparison, replyDepth)) { } - - /// - /// Initializes the attribute to filter messages where the replied-to message is from a user with specific names. - /// - /// The first name to match - /// The last name to match - /// How many levels up the reply chain to check (default: 1) - public RepliedFromUserAttribute(string firstName, string lastName, int replyDepth = 1) - : base(new RepliedUserFilter(firstName, lastName, StringComparison.InvariantCulture, replyDepth)) { } - - /// - /// Initializes the attribute to filter messages where the replied-to message is from a user with a specific first name. - /// - /// The first name to match - /// How many levels up the reply chain to check (default: 1) - public RepliedFromUserAttribute(string firstName, int replyDepth = 1) - : base(new RepliedUserFilter(firstName, null, StringComparison.InvariantCulture, replyDepth)) { } - - /// - /// Initializes the attribute to filter messages where the replied-to message is from a user with a specific first name and custom comparison. - /// - /// The first name to match - /// The string comparison method - /// How many levels up the reply chain to check (default: 1) - public RepliedFromUserAttribute(string firstName, StringComparison comparison, int replyDepth = 1) - : base(new RepliedUserFilter(firstName, null, comparison, replyDepth)) { } - } - - /// - /// Attribute for filtering messages based on the user ID of the sender of the replied-to message. - /// - /// The user ID to match - /// How many levels up the reply chain to check (default: 1) - public class RepliedUserIdAttribute(long userId, int replyDepth = 1) - : MessageFilterAttribute(new RepliedUserIdFilter(userId, replyDepth)) - { } - - /// - /// Attribute for filtering messages where the replied-to message was sent by a bot. - /// - /// How many levels up the reply chain to check (default: 1) - public class ReplyFromBotAttribute(int replyDepth = 1) - : MessageFilterAttribute(new ReplyFromBotFilter(replyDepth)) - { } - - /// - /// Attribute for filtering messages where the replied-to message was sent by a premium user. - /// - /// How many levels up the reply chain to check (default: 1) - public class ReplyFromPremiumUserAttribute(int replyDepth = 1) - : MessageFilterAttribute(new ReplyFromPremiumUserFilter(replyDepth)) - { } -} diff --git a/Telegrator/Annotations/RepliedMessageTextFilterAttributes.cs b/Telegrator/Annotations/RepliedMessageTextFilterAttributes.cs deleted file mode 100644 index 1764e0e..0000000 --- a/Telegrator/Annotations/RepliedMessageTextFilterAttributes.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Telegrator.Filters; - -namespace Telegrator.Annotations -{ - /// - /// Attribute for filtering updates where the replied-to message's text starts with the specified content. - /// - /// The string that the replied message's text should start with - /// The string comparison type - /// How many levels up the reply chain to check (default: 1) - public class RepliedTextStartsWithAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int replyDepth = 1) - : MessageFilterAttribute(new RepliedTextStartsWithFilter(content, comparison, replyDepth)) - { } - - /// - /// Attribute for filtering updates where the replied-to message's text ends with the specified content. - /// - /// The string that the replied message's text should end with - /// The string comparison type - /// How many levels up the reply chain to check (default: 1) - public class RepliedTextEndsWithAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int replyDepth = 1) - : MessageFilterAttribute(new RepliedTextEndsWithFilter(content, comparison, replyDepth)) - { } - - /// - /// Attribute for filtering updates where the replied-to message's text contains the specified content. - /// - /// The string that the replied message's text should contain - /// The string comparison type - /// How many levels up the reply chain to check (default: 1) - public class RepliedTextContainsAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int replyDepth = 1) - : MessageFilterAttribute(new RepliedTextContainsFilter(content, comparison, replyDepth)) - { } - - /// - /// Attribute for filtering updates where the replied-to message's text equals the specified content. - /// - /// The string that the replied message's text should equal - /// The string comparison type - /// How many levels up the reply chain to check (default: 1) - public class RepliedTextEqualsAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int replyDepth = 1) - : MessageFilterAttribute(new RepliedTextEqualsFilter(content, comparison, replyDepth)) - { } - - /// - /// Attribute for filtering updates where the replied-to message contains any non-empty text. - /// - /// How many levels up the reply chain to check (default: 1) - public class RepliedHasTextAttribute(int replyDepth = 1) - : MessageFilterAttribute(new RepliedTextNotNullOrEmptyFilter(replyDepth)) - { } -} diff --git a/Telegrator/Annotations/RepliedToMeAttribute.cs b/Telegrator/Annotations/RepliedToMeAttribute.cs deleted file mode 100644 index e183383..0000000 --- a/Telegrator/Annotations/RepliedToMeAttribute.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Telegrator.Filters; - -namespace Telegrator.Annotations -{ - /// - /// Attribute for filtering messages with reply to messages of this bot. - /// - public class RepliedToMeAttribute() - : MessageFilterAttribute(new RepliedToMeFilter()) - { } -} diff --git a/Telegrator/Filters/MentionedFilter.cs b/Telegrator/Filters/MentionedFilter.cs index a486188..d59233b 100644 --- a/Telegrator/Filters/MentionedFilter.cs +++ b/Telegrator/Filters/MentionedFilter.cs @@ -7,7 +7,7 @@ namespace Telegrator.Filters /// Filter that checks if a message contains a mention of the bot or a specific user. /// Requires a to be applied first to identify mention entities. /// - public class MentionedFilter : Filter + public class MentionedFilter : MessageFilterBase { /// /// The username to check for in the mention (null means check for bot's username). @@ -39,14 +39,14 @@ namespace Telegrator.Filters /// The filter execution context containing the message and completed filters. /// True if the message contains the specified mention; otherwise, false. /// Thrown when the bot username is null and no specific mention is provided. - public override bool CanPass(FilterExecutionContext context) + protected override bool CanPassNext(FilterExecutionContext context) { - if (context.Input.Text == null) + if (Target.Text == null) return false; string userName = Mention ?? context.BotInfo.User.Username ?? throw new ArgumentNullException(nameof(context), "MentionedFilter requires BotInfo to be initialized"); MessageHasEntityFilter entityFilter = context.CompletedFilters.Get(0); - return entityFilter.FoundEntities.Any(ent => context.Input.Text.Substring(ent.Offset + 1, ent.Length - 1) == userName); + return entityFilter.FoundEntities.Any(ent => Target.Text.Substring(ent.Offset + 1, ent.Length - 1) == userName); } } } diff --git a/Telegrator/Filters/MessageChatFilters.cs b/Telegrator/Filters/MessageChatFilters.cs index 81b7c97..29908d8 100644 --- a/Telegrator/Filters/MessageChatFilters.cs +++ b/Telegrator/Filters/MessageChatFilters.cs @@ -7,7 +7,7 @@ namespace Telegrator.Filters /// /// Base class for filters that operate on the chat of the message being processed. /// - public abstract class MessageChatFilter : Filter + public abstract class MessageChatFilter : MessageFilterBase { /// /// Gets the chat of the message being processed. @@ -15,18 +15,18 @@ namespace Telegrator.Filters public Chat Chat { get; private set; } = null!; /// - public override bool CanPass(FilterExecutionContext context) + protected override bool CanPassNext(FilterExecutionContext context) { - Chat = context.Input.Chat; + Chat = Target.Chat; return CanPassNext(context.CreateChild(Chat)); } /// /// Determines whether the filter passes for the given chat context. /// - /// The filter execution context for the chat. + /// The filter execution context for the chat. /// True if the filter passes; otherwise, false. - protected abstract bool CanPassNext(FilterExecutionContext _); + protected abstract bool CanPassNext(FilterExecutionContext context); } /// diff --git a/Telegrator/Filters/MessageFilters.cs b/Telegrator/Filters/MessageFilters.cs index a72f03f..35dffee 100644 --- a/Telegrator/Filters/MessageFilters.cs +++ b/Telegrator/Filters/MessageFilters.cs @@ -1,15 +1,40 @@ using System.Text.RegularExpressions; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; -using Telegrator; using Telegrator.Filters.Components; namespace Telegrator.Filters { + /// + /// Base abstract class for all filter of updates + /// + public abstract class MessageFilterBase : Filter + { + /// + /// Target message for filterring + /// + protected Message Target { get; private set; } = null!; + + /// + public override bool CanPass(FilterExecutionContext context) + { + MessageRepliedFilter? repliedFilter = context.CompletedFilters.Get().SingleOrDefault(); + Target = repliedFilter?.Reply ?? context.Input; + return CanPassNext(context); + } + + /// + /// Determines whether the filter can pass for the given context. + /// + /// + /// + protected abstract bool CanPassNext(FilterExecutionContext context); + } + /// /// Filters messages by their . /// - public class MessageTypeFilter : Filter + public class MessageTypeFilter : MessageFilterBase { private readonly MessageType type; @@ -20,54 +45,54 @@ namespace Telegrator.Filters public MessageTypeFilter(MessageType type) => this.type = type; /// - public override bool CanPass(FilterExecutionContext context) - => context.Input.Type == type; + protected override bool CanPassNext(FilterExecutionContext context) + => Target.Type == type; } /// /// Filters messages that are automatic forwards. /// - public class IsAutomaticFormwardMessageFilter : Filter + public class IsAutomaticFormwardMessageFilter : MessageFilterBase { /// - public override bool CanPass(FilterExecutionContext context) - => context.Input.IsAutomaticForward; + protected override bool CanPassNext(FilterExecutionContext context) + => Target.IsAutomaticForward; } /// /// Filters messages that are sent from offline. /// - public class IsFromOfflineMessageFilter : Filter + public class IsFromOfflineMessageFilter : MessageFilterBase { /// - public override bool CanPass(FilterExecutionContext context) - => context.Input.IsFromOffline; + protected override bool CanPassNext(FilterExecutionContext context) + => Target.IsFromOffline; } /// /// Filters service messages (e.g., chat events). /// - public class IsServiceMessageMessageFilter : Filter + public class IsServiceMessageMessageFilter : MessageFilterBase { /// - public override bool CanPass(FilterExecutionContext context) - => context.Input.IsServiceMessage; + protected override bool CanPassNext(FilterExecutionContext context) + => Target.IsServiceMessage; } /// /// Filters messages that are topic messages. /// - public class IsTopicMessageMessageFilter : Filter + public class IsTopicMessageMessageFilter : MessageFilterBase { /// - public override bool CanPass(FilterExecutionContext context) - => context.Input.IsTopicMessage; + protected override bool CanPassNext(FilterExecutionContext context) + => Target.IsTopicMessage; } /// /// Filters messages by dice throw value and optionally by dice type. /// - public class DiceThrowedFilter : Filter + public class DiceThrowedFilter : MessageFilterBase { private readonly DiceType? Dice; private readonly int Value; @@ -89,15 +114,15 @@ namespace Telegrator.Filters public DiceThrowedFilter(DiceType diceType, int value) : this(value) => Dice = diceType; /// - public override bool CanPass(FilterExecutionContext context) + protected override bool CanPassNext(FilterExecutionContext context) { - if (context.Input.Dice == null) + if (Target.Dice == null) return false; - if (Dice != null && context.Input.Dice.Emoji != GetEmojyForDiceType(Dice)) + if (Dice != null && Target.Dice.Emoji != GetEmojyForDiceType(Dice)) return false; - return context.Input.Dice.Value == Value; + return Target.Dice.Value == Value; } private static string? GetEmojyForDiceType(DiceType? diceType) => diceType switch @@ -136,7 +161,7 @@ namespace Telegrator.Filters /// /// Filters messages that contain a specific entity type, content, offset, or length. /// - public class MessageHasEntityFilter : Filter + public class MessageHasEntityFilter : MessageFilterBase { private readonly StringComparison _stringComparison = StringComparison.CurrentCulture; private readonly MessageEntityType? EntityType; @@ -202,12 +227,12 @@ namespace Telegrator.Filters } /// - public override bool CanPass(FilterExecutionContext context) + protected override bool CanPassNext(FilterExecutionContext context) { if (context.Input is not { Entities.Length: > 0 }) return false; - FoundEntities = context.Input.Entities.Where(entity => FilterEntity(context.Input.Text, entity)).ToArray(); + FoundEntities = Target.Entities.Where(entity => FilterEntity(Target.Text, entity)).ToArray(); return FoundEntities.Length != 0; } diff --git a/Telegrator/Filters/MessageRepliedFilters.cs b/Telegrator/Filters/MessageRepliedFilters.cs new file mode 100644 index 0000000..4a84334 --- /dev/null +++ b/Telegrator/Filters/MessageRepliedFilters.cs @@ -0,0 +1,62 @@ +using Telegram.Bot.Types; +using Telegrator.Filters.Components; + +namespace Telegrator.Filters +{ + /// + /// Abstract base class for filters that operate on replied messages. + /// Provides functionality to traverse reply chains and access replied message content. + /// + /// The depth of reply chain to traverse (default: 1). + public class MessageRepliedFilter(int replyDepth = 1) : Filter + { + /// + /// Gets the replied message at the specified depth in the reply chain. + /// + public Message Reply { get; private set; } = null!; + + /// + /// Gets the depth of reply chain traversal. + /// + public int ReplyDepth { get; private set; } = replyDepth; + + /// + /// Determines if the message can pass through the filter by first validating + /// the reply chain and then applying specific filter logic. + /// + /// The filter execution context containing the message. + /// True if the message passes both reply validation and specific filter criteria; otherwise, false. + public override bool CanPass(FilterExecutionContext context) + { + Message reply = context.Input; + for (int i = ReplyDepth; i > 0; i--) + { + if (reply.ReplyToMessage is not { Id: > 0 } replyMessage) + return false; + + reply = replyMessage; + } + + Reply = reply; + return true; + } + } + + /// + /// Filter that checks if the replied message was sent by the bot itself. + /// ( ! ): REQUIRES before + /// + public class MeRepliedFilter : Filter + { + /// + /// Checks if the replied message was sent by the bot. + /// + /// The filter execution context containing bot information. + /// True if the replied message was sent by the bot; otherwise, false. + public override bool CanPass(FilterExecutionContext context) + { + MessageRepliedFilter repliedFilter = context.CompletedFilters.Get(0); + return context.BotInfo.User == repliedFilter.Reply.From; + } + } +} diff --git a/Telegrator/Filters/MessageSenderFilters.cs b/Telegrator/Filters/MessageSenderFilters.cs index 0122b75..108573e 100644 --- a/Telegrator/Filters/MessageSenderFilters.cs +++ b/Telegrator/Filters/MessageSenderFilters.cs @@ -7,7 +7,7 @@ namespace Telegrator.Filters /// Abstract base class for filters that operate on message senders. /// Provides functionality to access and validate the user who sent the message. /// - public abstract class MessageSenderFilter : Filter + public abstract class MessageSenderFilter : MessageFilterBase { /// /// Gets the user who sent the message. @@ -22,20 +22,15 @@ namespace Telegrator.Filters /// True if the message has a valid sender; otherwise, false. public override bool CanPass(FilterExecutionContext context) { - User = context.Input.From!; + if (!base.CanPass(context)) + return false; + + User = Target.From!; if (User is not { Id: > 0 }) return false; return CanPassNext(context); } - - /// - /// Abstract method that must be implemented by derived classes to perform - /// specific filtering logic on the message sender. - /// - /// The filter execution context. - /// True if the sender passes the specific filter criteria; otherwise, false. - protected abstract bool CanPassNext(FilterExecutionContext context); } /// diff --git a/Telegrator/Filters/MessageTextFilters.cs b/Telegrator/Filters/MessageTextFilters.cs index d9e84d1..3f396b6 100644 --- a/Telegrator/Filters/MessageTextFilters.cs +++ b/Telegrator/Filters/MessageTextFilters.cs @@ -9,7 +9,7 @@ namespace Telegrator.Filters /// Abstract base class for filters that operate on message text content. /// Provides common functionality for extracting and validating message text. /// - public abstract class MessageTextFilter : Filter + public abstract class MessageTextFilter : MessageFilterBase { /// /// Gets the current message being processed by the filter. @@ -29,6 +29,9 @@ namespace Telegrator.Filters /// True if the message is valid and can be processed further; otherwise, false. public override bool CanPass(FilterExecutionContext context) { + if (!base.CanPass(context)) + return false; + Message = context.Update.Message!; if (Message is not { Id: > 0 }) return false; @@ -36,14 +39,6 @@ namespace Telegrator.Filters Text = Message.Text ?? string.Empty; return CanPassNext(context); } - - /// - /// Abstract method that must be implemented by derived classes to perform - /// specific text-based filtering logic. - /// - /// The filter execution context (unused in this context). - /// True if the text content passes the filter criteria; otherwise, false. - protected abstract bool CanPassNext(FilterExecutionContext _); } /// diff --git a/Telegrator/Filters/RepliedMentionedFilter.cs b/Telegrator/Filters/RepliedMentionedFilter.cs deleted file mode 100644 index e64f817..0000000 --- a/Telegrator/Filters/RepliedMentionedFilter.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Telegram.Bot.Types; -using Telegrator.Filters.Components; - -namespace Telegrator.Filters -{ - /// - /// Filter that checks if a replied message contains a mention of the bot or a specific user. - /// Requires a to be applied first to identify mention entities. - /// - public class RepliedMentionedFilter : RepliedMessageFilter - { - /// - /// The username to check for in the mention (null means check for bot's username). - /// - private readonly string? Mention; - - /// - /// Initializes a new instance of the class that checks for bot mentions. - /// - /// The depth of reply chain to traverse (default: 1). - public RepliedMentionedFilter(int replyDepth = 1) : base(replyDepth) - { - Mention = null; - } - - /// - /// Initializes a new instance of the class that checks for specific user mentions. - /// - /// The username to check for in the mention. - /// The depth of reply chain to traverse (default: 1). - public RepliedMentionedFilter(string mention, int replyDepth = 1) : base(replyDepth) - { - Mention = mention; - } - - /// - /// Checks if the replied message contains a mention of the specified user or bot. - /// This filter requires a to be applied first - /// to identify mention entities in the replied message. - /// - /// The filter execution context containing the message and completed filters. - /// True if the replied message contains the specified mention; otherwise, false. - /// Thrown when the bot username is null and no specific mention is provided. - protected override bool CanPassNext(FilterExecutionContext context) - { - if (Reply.Text == null) - return false; - - string userName = Mention ?? context.BotInfo.User.Username ?? throw new ArgumentNullException(nameof(context), "RepliedMentionedFilter requires BotInfo to be initialized"); - MessageEntity entity = context.CompletedFilters.Get(0).FoundEntities.ElementAt(0); - - string mention = Reply.Text.Substring(entity.Offset + 1, entity.Length - 1); - return userName == mention; - } - } -} diff --git a/Telegrator/Filters/RepliedMessageChatFilters.cs b/Telegrator/Filters/RepliedMessageChatFilters.cs deleted file mode 100644 index aa3838e..0000000 --- a/Telegrator/Filters/RepliedMessageChatFilters.cs +++ /dev/null @@ -1,211 +0,0 @@ -using Telegram.Bot.Types; -using Telegram.Bot.Types.Enums; -using Telegrator.Filters.Components; - -namespace Telegrator.Filters -{ - /// - /// Base class for filters that operate on the chat of a replied message (the message being replied to). - /// The replyDepth parameter determines how many levels up the reply chain to search for the target message. - /// - public abstract class RepliedMessageChatFilter : RepliedMessageFilter - { - /// - /// Gets the chat of the replied message (the message being replied to at the specified depth). - /// - public Chat Chat { get; private set; } = null!; - - /// - /// Initializes a new instance of the class. - /// - /// The reply depth to search up the reply chain for the target message. - protected RepliedMessageChatFilter(int replyDepth = 1) : base(replyDepth) { } - - /// - public override bool CanPass(FilterExecutionContext context) - { - if (!CanPassReply(context)) - return false; - - Chat = Reply.Chat; - return CanPassNext(context); - } - } - - /// - /// Filters replied messages (the message being replied to at the specified depth) whose chat is a forum. - /// - public class RepliedMessageChatIsForumFilter : RepliedMessageChatFilter - { - /// - /// Initializes a new instance of the class. - /// - /// The reply depth to search up the reply chain for the target message. - public RepliedMessageChatIsForumFilter(int replyDepth = 1) - : base(replyDepth) { } - - /// - protected override bool CanPassNext(FilterExecutionContext _) - => Chat.IsForum; - } - - /// - /// Filters replied messages (the message being replied to at the specified depth) whose chat ID matches the specified value. - /// - public class RepliedMessageChatIdFilter : RepliedMessageChatFilter - { - private readonly long Id; - - /// - /// Initializes a new instance of the class. - /// - /// The chat ID to match. - /// The reply depth to search up the reply chain for the target message. - public RepliedMessageChatIdFilter(long id, int replyDepth = 1) : base(replyDepth) => Id = id; - - /// - protected override bool CanPassNext(FilterExecutionContext _) - => Chat.Id == Id; - } - - /// - /// Filters replied messages (the message being replied to at the specified depth) whose chat type matches the specified value. - /// - public class RepliedMessageChatTypeFilter : RepliedMessageChatFilter - { - private readonly ChatType Type; - - /// - /// Initializes a new instance of the class. - /// - /// The chat type to match. - /// The reply depth to search up the reply chain for the target message. - public RepliedMessageChatTypeFilter(ChatType type, int replyDepth = 1) : base(replyDepth) => Type = type; - - /// - protected override bool CanPassNext(FilterExecutionContext _) - => Chat.Type == Type; - } - - /// - /// Filters replied messages (the message being replied to at the specified depth) whose chat title matches the specified value. - /// - public class RepliedMessageChatTitleFilter : RepliedMessageChatFilter - { - private readonly string? Title; - private readonly StringComparison Comparison = StringComparison.InvariantCulture; - - /// - /// Initializes a new instance of the class. - /// - /// The chat title to match. - /// The reply depth to search up the reply chain for the target message. - public RepliedMessageChatTitleFilter(string? title, int replyDepth = 1) : base(replyDepth) => Title = title; - - /// - /// Initializes a new instance of the class with a specific string comparison. - /// - /// The chat title to match. - /// The string comparison to use. - /// The reply depth to search up the reply chain for the target message. - public RepliedMessageChatTitleFilter(string? title, StringComparison comparison, int replyDepth = 1) - : this(title, replyDepth) => Comparison = comparison; - - /// - protected override bool CanPassNext(FilterExecutionContext _) - { - if (Chat.Title == null) - return false; - return Chat.Title.Equals(Title, Comparison); - } - } - - /// - /// Filters replied messages (the message being replied to at the specified depth) whose chat username matches the specified value. - /// - public class RepliedMessageChatUsernameFilter : RepliedMessageChatFilter - { - private readonly string? UserName; - private readonly StringComparison Comparison = StringComparison.InvariantCulture; - - /// - /// Initializes a new instance of the class. - /// - /// The chat username to match. - /// The reply depth to search up the reply chain for the target message. - public RepliedMessageChatUsernameFilter(string? userName, int replyDepth = 1) : base(replyDepth) => UserName = userName; - - /// - /// Initializes a new instance of the class with a specific string comparison. - /// - /// The chat username to match. - /// The string comparison to use. - /// The reply depth to search up the reply chain for the target message. - public RepliedMessageChatUsernameFilter(string? userName, StringComparison comparison, int replyDepth = 1) - : this(userName, replyDepth) => Comparison = comparison; - - /// - protected override bool CanPassNext(FilterExecutionContext _) - { - if (Chat.Username == null) - return false; - return Chat.Username.Equals(UserName, Comparison); - } - } - - /// - /// Filters replied messages (the message being replied to at the specified depth) whose chat first and/or last name matches the specified values. - /// - public class RepliedMessageChatNameFilter : RepliedMessageChatFilter - { - private readonly string? FirstName; - private readonly string? LastName; - private readonly StringComparison Comparison = StringComparison.InvariantCulture; - - /// - /// Initializes a new instance of the class. - /// - /// The chat first name to match. - /// The chat last name to match. - /// The reply depth to search up the reply chain for the target message. - public RepliedMessageChatNameFilter(string? firstName, string? lastName, int replyDepth = 1) : base(replyDepth) - { - FirstName = firstName; - LastName = lastName; - } - - /// - /// Initializes a new instance of the class with a specific string comparison. - /// - /// The chat first name to match. - /// The chat last name to match. - /// The string comparison to use. - /// The reply depth to search up the reply chain for the target message. - public RepliedMessageChatNameFilter(string? firstName, string? lastName, StringComparison comparison, int replyDepth = 1) - : this(firstName, lastName, replyDepth) => Comparison = comparison; - - /// - protected override bool CanPassNext(FilterExecutionContext _) - { - if (LastName != null) - { - if (Chat.LastName == null) - return false; - - if (Chat.LastName.Equals(LastName, Comparison)) - return false; - } - - if (FirstName != null) - { - if (Chat.FirstName == null) - return false; - - if (Chat.FirstName.Equals(FirstName, Comparison)) - return false; - } - - return true; - } - } -} diff --git a/Telegrator/Filters/RepliedMessageFilters.cs b/Telegrator/Filters/RepliedMessageFilters.cs deleted file mode 100644 index 17e1300..0000000 --- a/Telegrator/Filters/RepliedMessageFilters.cs +++ /dev/null @@ -1,383 +0,0 @@ -using Telegram.Bot.Types; -using Telegram.Bot.Types.Enums; -using Telegrator; -using Telegrator.Filters.Components; - -namespace Telegrator.Filters -{ - /// - /// Abstract base class for filters that operate on replied messages. - /// Provides functionality to traverse reply chains and access replied message content. - /// - /// The depth of reply chain to traverse (default: 1). - public abstract class RepliedMessageFilter(int replyDepth = 1) : Filter - { - /// - /// Gets the replied message at the specified depth in the reply chain. - /// - public Message Reply { get; private set; } = null!; - - /// - /// Gets the depth of reply chain traversal. - /// - public int ReplyDepth { get; private set; } = replyDepth; - - /// - /// Validates that the message has a valid reply chain at the specified depth. - /// - /// The filter execution context containing the message. - /// True if the reply chain is valid at the specified depth; otherwise, false. - protected bool CanPassReply(FilterExecutionContext context) - { - Message reply = context.Input; - for (int i = ReplyDepth; i > 0; i--) - { - if (reply.ReplyToMessage is not { Id: > 0 } replyMessage) - return false; - - reply = replyMessage; - } - - Reply = reply; - return true; - } - - /// - /// Determines if the message can pass through the filter by first validating - /// the reply chain and then applying specific filter logic. - /// - /// The filter execution context containing the message. - /// True if the message passes both reply validation and specific filter criteria; otherwise, false. - public override bool CanPass(FilterExecutionContext context) - { - if (!CanPassReply(context)) - return false; - - return CanPassNext(context); - } - - /// - /// Abstract method that must be implemented by derived classes to perform - /// specific filtering logic on the replied message. - /// - /// The filter execution context. - /// True if the replied message passes the specific filter criteria; otherwise, false. - protected abstract bool CanPassNext(FilterExecutionContext context); - } - - /// - /// Filter that checks if a message is a reply to another message at the specified depth. - /// - /// The depth of reply chain to traverse (default: 1). - public class MessageRepliedFilter(int replyDepth = 1) : RepliedMessageFilter(replyDepth) - { - /// - /// Always returns true if the reply chain is valid at the specified depth. - /// - /// The filter execution context (unused). - /// True if the reply chain is valid; otherwise, false. - protected override bool CanPassNext(FilterExecutionContext context) - => true; - } - - /// - /// Filter that checks if the replied message was sent by the bot itself. - /// - /// The depth of reply chain to traverse (default: 1). - public class MeRepliedFilter(int replyDepth = 1) : RepliedMessageFilter(replyDepth) - { - /// - /// Checks if the replied message was sent by the bot. - /// - /// The filter execution context containing bot information. - /// True if the replied message was sent by the bot; otherwise, false. - protected override bool CanPassNext(FilterExecutionContext context) - => context.BotInfo.User == Reply.From; - } - - /// - /// Filter that checks if the replied message has non-empty text content. - /// - /// The depth of reply chain to traverse (default: 1). - public class RepliedTextNotNullOrEmptyFilter(int replyDepth = 1) : RepliedMessageFilter(replyDepth) - { - /// - /// Checks if the replied message text is not null or empty. - /// - /// The filter execution context (unused). - /// True if the replied message has non-empty text; otherwise, false. - protected override bool CanPassNext(FilterExecutionContext _) - => !string.IsNullOrEmpty(Reply.Text); - } - - /// - /// Filter that checks if the replied message is of a specific type. - /// - /// The message type to check for. - /// The depth of reply chain to traverse (default: 1). - public class RepliedMessageTypeFilter(MessageType type, int replyDepth = 1) : RepliedMessageFilter(replyDepth) - { - /// - /// Checks if the replied message is of the specified type. - /// - /// The filter execution context (unused). - /// True if the replied message is of the specified type; otherwise, false. - protected override bool CanPassNext(FilterExecutionContext _) - => Reply.Type == type; - } - - /// - /// Filter that checks if the replied message is an automatic forward. - /// - /// The depth of reply chain to traverse (default: 1). - public class RepliedIsAutomaticFormwardMessageFilter(int replyDepth = 1) : RepliedMessageFilter(replyDepth) - { - /// - /// Checks if the replied message is an automatic forward. - /// - /// The filter execution context (unused). - /// True if the replied message is an automatic forward; otherwise, false. - protected override bool CanPassNext(FilterExecutionContext _) - => Reply.IsAutomaticForward; - } - - /// - /// Filter that checks if the replied message is from an offline user. - /// - /// The depth of reply chain to traverse (default: 1). - public class RepliedIsFromOfflineMessageFilter(int replyDepth = 1) : RepliedMessageFilter(replyDepth) - { - /// - /// Checks if the replied message is from an offline user. - /// - /// The filter execution context (unused). - /// True if the replied message is from an offline user; otherwise, false. - protected override bool CanPassNext(FilterExecutionContext _) - => Reply.IsFromOffline; - } - - /// - /// Filter that checks if the replied message is a service message. - /// - /// The depth of reply chain to traverse (default: 1). - public class RepliedIsServiceMessageMessageFilter(int replyDepth = 1) : RepliedMessageFilter(replyDepth) - { - /// - /// Checks if the replied message is a service message. - /// - /// The filter execution context (unused). - /// True if the replied message is a service message; otherwise, false. - protected override bool CanPassNext(FilterExecutionContext _) - => Reply.IsServiceMessage; - } - - /// - /// Filter that checks if the replied message is a topic message. - /// - /// The depth of reply chain to traverse (default: 1). - public class RepliedIsTopicMessageMessageFilter(int replyDepth = 1) : RepliedMessageFilter(replyDepth) - { - /// - /// Checks if the replied message is a topic message. - /// - /// The filter execution context (unused). - /// True if the replied message is a topic message; otherwise, false. - protected override bool CanPassNext(FilterExecutionContext _) - => Reply.IsTopicMessage; - } - - /// - /// Filter that checks if the replied message contains a dice with a specific value. - /// - /// The dice value to check for. - /// The depth of reply chain to traverse (default: 1). - public class RepliedDiceThrowedFilter(int value, int replyDepth = 1) : RepliedMessageFilter(replyDepth) - { - /// - /// The dice type to check for (optional). - /// - private readonly DiceType? Dice = null; - - /// - /// The dice value to check for. - /// - private readonly int Value = value; - - /// - /// Initializes a new instance of the class with a specific dice type and value. - /// - /// The dice type to check for. - /// The dice value to check for. - /// The depth of reply chain to traverse (default: 1). - public RepliedDiceThrowedFilter(DiceType diceType, int value, int replyDepth = 1) - : this(value, replyDepth) => Dice = diceType; - - /// - /// Checks if the replied message contains a dice with the specified value and optionally the specified type. - /// - /// The filter execution context containing the message. - /// True if the replied message contains a dice with the specified criteria; otherwise, false. - protected override bool CanPassNext(FilterExecutionContext context) - { - if (context.Input.Dice == null) - return false; - - if (Dice != null && context.Input.Dice.Emoji != GetEmojyForDiceType(Dice)) - return false; - - return context.Input.Dice.Value == Value; - } - - /// - /// Gets the emoji representation for a specific dice type. - /// - /// The dice type to get the emoji for. - /// The emoji string for the dice type, or null if not found. - private static string? GetEmojyForDiceType(DiceType? diceType) => diceType switch - { - DiceType.Dice => "🎲", - DiceType.Darts => "🎯", - DiceType.Bowling => "🎳", - DiceType.Basketball => "🏀", - DiceType.Football => "⚽", - DiceType.Casino => "🎰", - _ => null - }; - } - - /// - /// Filter that checks if the replied message contains specific message entities. - /// - /// The depth of reply chain to traverse (default: 1). - public class RepliedMessageHasEntityFilter(int replyDepth = 1) : RepliedMessageFilter(replyDepth) - { - /// - /// The string comparison type to use for content matching. - /// - private readonly StringComparison _stringComparison = StringComparison.CurrentCulture; - - /// - /// The entity type to filter by (optional). - /// - private readonly MessageEntityType? EntityType; - - /// - /// The content to match in the entity (optional). - /// - private readonly string? Content; - - /// - /// The offset position to check (optional). - /// - private readonly int? Offset; - - /// - /// The length to check (optional). - /// - private readonly int? Length; - - /// - /// Gets the found entities that match the filter criteria. - /// - public MessageEntity[]? FoundEntities { get; set; } = null!; - - /// - /// Initializes a new instance of the class with a specific entity type. - /// - /// The entity type to filter by. - /// The depth of reply chain to traverse (default: 1). - public RepliedMessageHasEntityFilter(MessageEntityType type, int replyDepth = 1) : this(replyDepth) - { - EntityType = type; - } - - /// - /// Initializes a new instance of the class with position criteria. - /// - /// The entity type to filter by. - /// The offset position to check. - /// The length to check (optional). - /// The depth of reply chain to traverse (default: 1). - public RepliedMessageHasEntityFilter(MessageEntityType type, int offset, int? length, int replyDepth = 1) : this(replyDepth) - { - EntityType = type; - Offset = offset; - Length = length; - } - - /// - /// Initializes a new instance of the class with content criteria. - /// - /// The entity type to filter by. - /// The content to match in the entity. - /// The string comparison type to use. - /// The depth of reply chain to traverse (default: 1). - public RepliedMessageHasEntityFilter(MessageEntityType type, string content, StringComparison stringComparison = StringComparison.CurrentCulture, int replyDepth = 1) : this(replyDepth) - { - EntityType = type; - Content = content; - _stringComparison = stringComparison; - } - - /// - /// Initializes a new instance of the class with all criteria. - /// - /// The entity type to filter by. - /// The offset position to check. - /// The length to check (optional). - /// The content to match in the entity. - /// The string comparison type to use. - /// The depth of reply chain to traverse (default: 1). - public RepliedMessageHasEntityFilter(MessageEntityType type, int offset, int? length, string content, StringComparison stringComparison = StringComparison.CurrentCulture, int replyDepth = 1) : this(replyDepth) - { - EntityType = type; - Offset = offset; - Length = length; - Content = content; - _stringComparison = stringComparison; - } - - /// - /// Checks if the replied message contains entities that match the specified criteria. - /// - /// The filter execution context containing the message. - /// True if matching entities are found; otherwise, false. - protected override bool CanPassNext(FilterExecutionContext context) - { - if (context.Input is not { Entities.Length: > 0 }) - return false; - - FoundEntities = context.Input.Entities.Where(entity => FilterEntity(context.Input.Text, entity)).ToArray(); - return FoundEntities.Length != 0; - } - - /// - /// Filters an entity based on the specified criteria. - /// - /// The message text containing the entity. - /// The entity to filter. - /// True if the entity matches all specified criteria; otherwise, false. - private bool FilterEntity(string? text, MessageEntity entity) - { - if (EntityType != null && entity.Type != EntityType) - return false; - - if (Offset != null && entity.Offset != Offset) - return false; - - if (Length != null && entity.Length != Length) - return false; - - if (Content != null) - { - if (text is not { Length: > 0 }) - return false; - - if (!text.Substring(entity.Offset, entity.Length).Equals(Content, _stringComparison)) - return false; - } - - return true; - } - } -} diff --git a/Telegrator/Filters/RepliedMessageSenderFilters.cs b/Telegrator/Filters/RepliedMessageSenderFilters.cs deleted file mode 100644 index 1813753..0000000 --- a/Telegrator/Filters/RepliedMessageSenderFilters.cs +++ /dev/null @@ -1,192 +0,0 @@ -using Telegram.Bot.Types; -using Telegrator.Filters.Components; - -namespace Telegrator.Filters -{ - /// - /// Abstract base class for filters that operate on the sender of replied messages. - /// Provides functionality to access and validate the user who sent the replied message. - /// - /// The depth of reply chain to traverse (default: 1). - public abstract class RepliedMessageSenderFilter(int replyDepth = 1) : RepliedMessageFilter(replyDepth) - { - /// - /// Gets the user who sent the replied message. - /// - public User User { get; private set; } = null!; - - /// - /// Determines if the message can pass through the filter by validating the reply chain - /// and ensuring the replied message has a valid sender. - /// - /// The filter execution context containing the message. - /// True if the reply chain is valid and has a sender; otherwise, false. - public override bool CanPass(FilterExecutionContext context) - { - if (!CanPassReply(context)) - return false; - - if (Reply.From is not { Id: > 0 } from) - return false; - - User = from; - return CanPassNext(context); - } - } - - /// - /// Filter that checks if the replied message sender has a specific username. - /// - /// The username to check for. - /// The depth of reply chain to traverse (default: 1). - public class RepliedUsernameFilter(string username, int replyDepth = 1) : RepliedMessageSenderFilter(replyDepth) - { - /// - /// The username to check for. - /// - private readonly string _username = username; - - /// - /// The string comparison type to use for username matching. - /// - private readonly StringComparison _comparison = StringComparison.InvariantCulture; - - /// - /// Initializes a new instance of the class with custom string comparison. - /// - /// The username to check for. - /// The string comparison type to use. - /// The depth of reply chain to traverse (default: 1). - public RepliedUsernameFilter(string username, StringComparison comparison, int replyDepth = 1) - : this(username, replyDepth) => _comparison = comparison; - - /// - /// Checks if the replied message sender has the specified username. - /// - /// The filter execution context (unused). - /// True if the sender has the specified username; otherwise, false. - protected override bool CanPassNext(FilterExecutionContext context) - => User.Username != null && User.Username.Equals(_username, _comparison); - } - - /// - /// Filter that checks if the replied message sender has specific first and/or last name. - /// - /// The first name to check for. - /// The last name to check for (optional). - /// The string comparison type to use. - /// The depth of reply chain to traverse (default: 1). - public class RepliedUserFilter(string firstName, string? lastName, StringComparison comparison, int replyDepth = 1) : RepliedMessageSenderFilter(replyDepth) - { - /// - /// The first name to check for. - /// - private readonly string _firstName = firstName; - - /// - /// The last name to check for (optional). - /// - private readonly string? _lastName = lastName; - - /// - /// The string comparison type to use for name matching. - /// - private readonly StringComparison _comparison = comparison; - - /// - /// Initializes a new instance of the class with first and last name. - /// - /// The first name to check for. - /// The last name to check for. - /// The depth of reply chain to traverse (default: 1). - public RepliedUserFilter(string firstName, string lastName, int replyDepth = 1) - : this(firstName, lastName, StringComparison.InvariantCulture, replyDepth) { } - - /// - /// Initializes a new instance of the class with first name only. - /// - /// The first name to check for. - /// The depth of reply chain to traverse (default: 1). - public RepliedUserFilter(string firstName, int replyDepth = 1) - : this(firstName, null, StringComparison.InvariantCulture, replyDepth) { } - - /// - /// Initializes a new instance of the class with first name and custom comparison. - /// - /// The first name to check for. - /// The string comparison type to use. - /// The depth of reply chain to traverse (default: 1). - public RepliedUserFilter(string firstName, StringComparison comparison, int replyDepth = 1) - : this(firstName, null, comparison, replyDepth) { } - - /// - /// Checks if the replied message sender has the specified first and/or last name. - /// - /// The filter execution context (unused). - /// True if the sender has the specified name(s); otherwise, false. - protected override bool CanPassNext(FilterExecutionContext context) - { - if (User.LastName != null) - { - if (_lastName == null) - return false; - - if (!_firstName.Equals(User.LastName, _comparison)) - return false; - } - - return User.FirstName.Equals(_firstName, _comparison); - } - } - - /// - /// Filter that checks if the replied message sender has a specific user ID. - /// - /// The user ID to check for. - /// The depth of reply chain to traverse (default: 1). - public class RepliedUserIdFilter(long userId, int replyDepth = 1) : RepliedMessageSenderFilter(replyDepth) - { - /// - /// The user ID to check for. - /// - private readonly long _userId = userId; - - /// - /// Checks if the replied message sender has the specified user ID. - /// - /// The filter execution context (unused). - /// True if the sender has the specified user ID; otherwise, false. - protected override bool CanPassNext(FilterExecutionContext _) - => User.Id == _userId; - } - - /// - /// Filter that checks if the replied message was sent by a bot. - /// - /// The depth of reply chain to traverse (default: 1). - public class ReplyFromBotFilter(int replyDepth = 1) : RepliedMessageSenderFilter(replyDepth) - { - /// - /// Checks if the replied message was sent by a bot. - /// - /// The filter execution context (unused). - /// True if the replied message was sent by a bot; otherwise, false. - protected override bool CanPassNext(FilterExecutionContext _) - => User.IsBot; - } - - /// - /// Filter that checks if the replied message was sent by a premium user. - /// - /// The depth of reply chain to traverse (default: 1). - public class ReplyFromPremiumUserFilter(int replyDepth = 1) : RepliedMessageSenderFilter(replyDepth) - { - /// - /// Checks if the replied message was sent by a premium user. - /// - /// The filter execution context (unused). - /// True if the replied message was sent by a premium user; otherwise, false. - protected override bool CanPassNext(FilterExecutionContext _) - => User.IsPremium; - } -} diff --git a/Telegrator/Filters/RepliedMessageTextFilters.cs b/Telegrator/Filters/RepliedMessageTextFilters.cs deleted file mode 100644 index 5a5af30..0000000 --- a/Telegrator/Filters/RepliedMessageTextFilters.cs +++ /dev/null @@ -1,123 +0,0 @@ -using Telegram.Bot.Types; -using Telegrator.Filters.Components; - -namespace Telegrator.Filters -{ - /// - /// Base class for filters that operate on the text of a replied message (the message being replied to). - /// The replyDepth parameter determines how many levels up the reply chain to search for the target message. - /// - public abstract class RepliedMessageTextFilters : RepliedMessageFilter - { - /// - /// Gets the text of the replied message (the message being replied to at the specified depth). - /// - public string Text { get; private set; } = null!; - - /// - /// The content to match in the replied message. - /// - protected readonly string Content; - - /// - /// The string comparison to use for matching. - /// - protected readonly StringComparison Comparison; - - /// - /// Initializes a new instance of the class. - /// - /// The content to match. - /// The string comparison to use. - /// The reply depth to search up the reply chain for the target message. - protected RepliedMessageTextFilters(string content, StringComparison comparison = StringComparison.InvariantCulture, int replyDepth = 1) - : base(replyDepth) - { - Content = content; - Comparison = comparison; - } - - /// - public override bool CanPass(FilterExecutionContext context) - { - Text = Reply.Text ?? string.Empty; - return CanPassNext(context); - } - } - - /// - /// Filters replied messages (the message being replied to at the specified depth) whose text starts with the specified content. - /// - public class RepliedTextStartsWithFilter : RepliedMessageTextFilters - { - /// - /// Initializes a new instance of the class. - /// - /// The content to match. - /// The string comparison to use. - /// The reply depth to search up the reply chain for the target message. - public RepliedTextStartsWithFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int replyDepth = 1) - : base(content, comparison, replyDepth) { } - - /// - protected override bool CanPassNext(FilterExecutionContext _) - => Text.StartsWith(Content, Comparison); - } - - /// - /// Filters replied messages (the message being replied to at the specified depth) whose text ends with the specified content. - /// - public class RepliedTextEndsWithFilter : RepliedMessageTextFilters - { - /// - /// Initializes a new instance of the class. - /// - /// The content to match. - /// The string comparison to use. - /// The reply depth to search up the reply chain for the target message. - public RepliedTextEndsWithFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int replyDepth = 1) - : base(content, comparison, replyDepth) { } - - /// - protected override bool CanPassNext(FilterExecutionContext _) - => Text.EndsWith(Content, Comparison); - } - - /// - /// Filters replied messages (the message being replied to at the specified depth) whose text contains the specified content. - /// - public class RepliedTextContainsFilter : RepliedMessageTextFilters - { - /// - /// Initializes a new instance of the class. - /// - /// The content to match. - /// The string comparison to use. - /// The reply depth to search up the reply chain for the target message. - public RepliedTextContainsFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int replyDepth = 1) - : base(content, comparison, replyDepth) { } - - /// - protected override bool CanPassNext(FilterExecutionContext _) - => Text.IndexOf(Content, Comparison) >= 0; - } - - /// - /// Filters replied messages (the message being replied to at the specified depth) whose text equals the specified content. - /// - public class RepliedTextEqualsFilter : RepliedMessageTextFilters - { - /// - /// Initializes a new instance of the class. - /// - /// The content to match. - /// The string comparison to use. - /// The reply depth to search up the reply chain for the target message. - public RepliedTextEqualsFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int replyDepth = 1) - : base(content, comparison, replyDepth) { } - - /// - protected override bool CanPassNext(FilterExecutionContext _) - => Text.Equals(Content, Comparison); - } -} diff --git a/Telegrator/Filters/RepliedToMeFilter.cs b/Telegrator/Filters/RepliedToMeFilter.cs deleted file mode 100644 index 892e774..0000000 --- a/Telegrator/Filters/RepliedToMeFilter.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Telegram.Bot.Types; -using Telegrator.Filters.Components; - -namespace Telegrator.Filters -{ - public class RepliedToMeFilter : RepliedMessageFilter - { - protected override bool CanPassNext(FilterExecutionContext context) - { - if (Reply.From == null) - return false; - - return Reply.From.Id == (context.BotInfo?.User.Id ?? throw new ArgumentNullException(nameof(context), "MentionedFilter requires BotInfo to be initialized")); - } - } -} diff --git a/Telegrator/IReactiveTelegramBot.cs b/Telegrator/ITelegratorBot.cs similarity index 90% rename from Telegrator/IReactiveTelegramBot.cs rename to Telegrator/ITelegratorBot.cs index 684aea8..95b262b 100644 --- a/Telegrator/IReactiveTelegramBot.cs +++ b/Telegrator/ITelegratorBot.cs @@ -6,7 +6,7 @@ namespace Telegrator /// Interface for reactive Telegram bot implementations. /// Defines the core properties and capabilities of a reactive bot. /// - public interface IReactiveTelegramBot + public interface ITelegratorBot { /// /// Gets the update router for handling incoming updates. diff --git a/Telegrator/TelegratorClient.cs b/Telegrator/TelegratorClient.cs index 1e6a7e8..94b443b 100644 --- a/Telegrator/TelegratorClient.cs +++ b/Telegrator/TelegratorClient.cs @@ -11,7 +11,7 @@ namespace Telegrator /// Main client class for the Telegrator library. /// Extends TelegramBotClient with reactive capabilities for handling updates. /// - public class TelegratorClient : TelegramBotClient, IReactiveTelegramBot, ICollectingProvider + public class TelegratorClient : TelegramBotClient, ITelegratorBot, ICollectingProvider { /// /// The update router for handling incoming updates.