I need to check if a message sender is in a "special" list, to allow only special users to use some commands. I used IDFilter for it. But this "special" list may be changed, and I need these changes to be taken into account. But I found that IDFilter doesn’t consider them.
File test.py
:
from aiogram import Bot, Dispatcher, executor, types
from aiogram.dispatcher.filters.builtin import IDFilter
import config
bot = Bot(config.TOKEN)
dp = Dispatcher(bot)
@dp.message_handler(commands=['start'])
async def start_cmd(message: types.Message):
await message.reply(text='Hello!')
@dp.message_handler(commands=['secret'], user_id=config.mylist) # user_id - the simplest way to use IDFilter. Another way is like IDFilter(config.mylist), but put it before commands argument.
async def secret(message: types.Message):
await message.answer(text='Hello, this is a secret message only for ids in mylist!!!')
@dp.message_handler(commands=['clear'])
async def clear(message: types.Message):
config.mylist = []
await message.reply(f'Mylist is empty now: {", ".join([str(id) for id in config.mylist])}')
@dp.message_handler(commands=['add_me'])
async def add_me(message: types.Message):
config.mylist.append(message.from_user.id)
await message.answer(f'Your id was added to mylist: {", ".join([str(id) for id in config.mylist])}')
if __name__ == '__main__':
executor.start_polling(dp)
File config.py:
TOKEN = "<token here>"
mylist = [<my telegram id here>]
Here is the resulting bot:
So even though config.mylist
was empty, IDFilter’s verification was successful.
But if I use lambda message: message.from_user.id in config.mylist
, the changes of the list are considered.
Why is this happening?
2
Answers
If you will look at
aiogram.dispatcher.filters.builtin.py
file, and atIDFilter
class inside it, you can see that IDFilter on init extract ids from your arguments (config.mylist in my case) and creates copies of them, and then uses the copies for checking.So even if config.mylist is changed, the IDFilter doesn't consider this changing, because it has its own ids that were copied from the list, and they don't change.
So I will use the checking by lambda like
lambda message: message.from_user.id in config.mylist
.You might want to implement a decorator for that purpose. For example:
Note: the above solution is slightly different from yours conceptually: in the solution with the decorator unauthorized users are restricted from performing an action of the handler but they get to know that such an option exists for admins. With your solution, even the list of protected commands is hidden from your users (if a non-admin user attempts to use an admin command, the corresponding handler is not matched with your lambda, so the bot treats it as if such a command does not exist at all). Your method is generally more secure, but often it is not necessary to hide the list of commands available to the admins.
More on decorators: https://pythonbasics.org/decorators/