DEV Community

Cover image for Bot-Moderator for Telegram chats. Filters
Maksym Zavalniuk
Maksym Zavalniuk

Posted on

Bot-Moderator for Telegram chats. Filters

What are the filters? 💭

When we register a handler, we specify what command it should respond to, what type of message to accept, etc. For example:

@dp.message_handler(is_admin=True, commands=['kick'], commands_prefix='!/',
                    chat_type=[ChatType.GROUP, ChatType.SUPERGROUP])
async def kick_user(message: Message):
Enter fullscreen mode Exit fullscreen mode

As you can see, here the handler will be executed only when:

  1. this will be the kick command;
  2. the command starts with "!" or "/";
  3. The command is written in a group or supergroup.

These are all called filters. Somewhere deep in the library, handler registration takes place, where its filters are registered for each handler:

def register(self, handler, filters=None, index=None):
        """
        Register callback

        Filters can be awaitable or not.

        :param handler: coroutine
        :param filters: list of filters
        :param index: you can reorder handlers
        """
        from .filters import get_filters_spec

        spec = _get_spec(handler)

        if filters and not isinstance(filters, (list, tuple, set)):
            filters = [filters]
        filters = get_filters_spec(self.dispatcher, filters)

        record = Handler.HandlerObj(handler=handler, spec=spec, filters=filters)
        if index is None:
            self.handlers.append(record)
        else:
            self.handlers.insert(index, record)
Enter fullscreen mode Exit fullscreen mode

If we look at what the handle decorator accepts, we will see the following:

decorator preview

and today we will learn to create a custom filter.

Create your own filters ✍️

First, we need to create a file in the filters folder, for example, admin.py:

📦tgbot
┣ 📂filters
┃ ┣ 📜admin.py
┃ ┗ 📜init.py

and add the following code inside:

from aiogram import types
from aiogram.dispatcher.filters import BoundFilter


class IsAdminFilter(BoundFilter):
    key = 'is_admin'

    def __init__(self, is_admin):
        self.is_admin = is_admin

    async def check(self, message: types.Message) -> bool:
        member = await message.bot.get_chat_member(message.chat.id, message.from_user.id)
        return member.is_chat_admin()
Enter fullscreen mode Exit fullscreen mode

As you can see, the filter is a simple Python class that inherits a BoundFilter class that allows us to create our own filters. We have a field key = 'is_admin' that shows how we will describe our filter in the handlers. In addition to the structure, we have the main method async def check(). You can describe any of your logic inside it, but this method must return a Boolean value (True or False).

Connecting own filters ⛓️

Simply creating a class is not enough. Next, you need to go to the bot.py file, import out filter and bind it to the dispatcher:

...
from tgbot.config import load_config
from tgbot.services.setting_commands import set_default_commands
from tgbot.filters.admin import IsAdminFilter

...

def register_all_filters(dispatcher: Dispatcher) -> None:
    logger.info('Registering filters')
    dispatcher.filters_factory.bind(IsAdminFilter)
Enter fullscreen mode Exit fullscreen mode

Now we can add our filter to the handlers as I showed in the first picture. In this article, we will not yet write handlers for administering chats.

Additional part 😺

For now, let's program the handlers for the two commands: /start and /help:

  • tgbot/handlers/start.py:
from aiogram.types import Message
from aiogram.dispatcher.filters.builtin import CommandStart

from loader import dp


@dp.message_handler(CommandStart())
async def start_command(message: Message) -> Message:
    return await message.answer('Add a bot to the chat, give the administrator permissions and use it')
Enter fullscreen mode Exit fullscreen mode
  • tgbot/handlers/help.py:
from aiogram.types import Message
from aiogram.dispatcher.filters.builtin import CommandHelp

from loader import dp


@dp.message_handler(CommandHelp())
async def help_command(message: Message) -> Message:
    """
    This handler will be called when a user sends `/help` command
    """
    return await message.answer("""
User's command:
    /help - get commands
    /admins - get chat admins
    /dice - roll a dice
Administrator's command:
    !kick - kick a user
    !ban - ban a user
    !mute - mute a user
    !unmute, !unban - opposite commands
""")
Enter fullscreen mode Exit fullscreen mode

Here, the decorators have already used filters built into aiogram. The entire list of such filters can be found here.

References 🔗

Thank you for reading! ❤️ ❤️ ❤️

Top comments (0)